Loading the necessary packages for the project
library(tidyverse) # Loads ggplot2, dplyr, tidyr, readr, purrr, tibble, and stringr
── Attaching core tidyverse packages ─────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.3 ✔ readr 2.1.4
✔ forcats 1.0.0 ✔ stringr 1.5.0
✔ ggplot2 3.4.3 ✔ tibble 3.2.1
✔ lubridate 1.9.2 ✔ tidyr 1.3.0
✔ purrr 1.0.2 ── Conflicts ───────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(readxl) # For reading Excel files
library(rvest) # For web scraping
Attaching package: ‘rvest’
The following object is masked from ‘package:readr’:
guess_encoding
library(httr) # For working with HTTP
library(rcrossref) # For using CrossRef's API
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
library(janitor) # For cleaning data
Attaching package: ‘janitor’
The following objects are masked from ‘package:stats’:
chisq.test, fisher.test
library(reshape2) # For reshaping data
Attaching package: ‘reshape2’
The following object is masked from ‘package:tidyr’:
smiths
library(igraph) # For graphing
Attaching package: ‘igraph’
The following objects are masked from ‘package:lubridate’:
%--%, union
The following objects are masked from ‘package:dplyr’:
as_data_frame, groups, union
The following objects are masked from ‘package:purrr’:
compose, simplify
The following object is masked from ‘package:tidyr’:
crossing
The following object is masked from ‘package:tibble’:
as_data_frame
The following objects are masked from ‘package:stats’:
decompose, spectrum
The following object is masked from ‘package:base’:
union
library(ggraph) # For graphing
library(scales) # For graphing
Attaching package: ‘scales’
The following object is masked from ‘package:purrr’:
discard
The following object is masked from ‘package:readr’:
col_factor
library(lubridate) # For time series work
library(gridExtra) # For Grid making
Attaching package: ‘gridExtra’
The following object is masked from ‘package:dplyr’:
combine
library(VennDiagram)# For Venn Diagrams
Loading required package: grid
Loading required package: futile.logger
Loading the data-set sourced from Retraction Watch on
12-Jan-2024
data<- read.csv("retraction_watch.csv")
abdc<- read.csv("abdc.csv")
predatory<- read.csv("predatory.csv")
Doing some wrangling of the data
# Convert dates to POSIX format for the pupose of computation
data$OriginalPaperDate <- as.POSIXct(data$OriginalPaperDate, format = "%m/%d/%Y %H:%M")
data$RetractionDate <- as.POSIXct(data$RetractionDate, format = "%m/%d/%Y %H:%M")
# Compute the difference in months
data$DurationInMonths <- interval(start = data$OriginalPaperDate, end = data$RetractionDate) / months(1)
# Extract year from RetractionDate
data$RetractionYear <- year(data$RetractionDate)
#Creating Clean names
data<- data %>%
clean_names()
abdc<- abdc%>%
clean_names()
predatory<- predatory %>%
clean_names()
Creating the lists
abdc_list <- unique(tolower(abdc$journal))
retraction_list <- unique(tolower(data$journal))
predatory_list <- unique(tolower(predatory$journal))
Trying to create a venn diagram to see how these sets intersect
# Define a list of lists for the Venn diagram
list_of_lists <- list(
ABDC = abdc_list,
Retraction = retraction_list,
Predatory = predatory_list
)
# Specify the filename for the output
output_filename <- "venn_diagram.png"
# Create and save the Venn diagram
venn.plot <- venn.diagram(
x = list_of_lists,
category.names = c("ABDC", "Retraction", "Predatory"),
filename = output_filename
)
No Direct relationship between predatory practices and retractions:
The fact that there are many retractions not linked to predatory
journals might suggest that predatory practices are not the only reason
for retractions. Retractions can occur in any journal and may be due to
factors like data fabrication, plagiarism, or other ethical issues.
Overlap between predatory and retraction: There is an overlap of just
one journal between the predatory list and the ABDC list, suggesting
that the ABDC list is largely successful in avoiding predatory journals.
However, the presence of that one journal indicates that no vetting
process is completely foolproof.
Retractions are not limited to Predatory Journals: The larger number
of retractions (7820) not associated with predatory journals implies
that retractions are a broader issue in academic publishing, potentially
due to factors like honest errors, misconduct, or problems in the
peer-review process even in non-predatory journals.
Considering only one predatory journal of the 1147 that are listed,
has ever had a retracted article in it, is there something that we are
overseeing?
Filter data for rows where article_type is “Research Article” or
“Article in Press”
# This is to ensure that there are no conference papers, book chapters, and others that are there in the dataset. Our research is limited to journal publications only.
filtered_data <- data[grepl("Research Article", data$article_type) | grepl("Article in Press", data$article_type), ]
Looking only at the intersection of ABDC and Retracted.
ret_int_abdc <- filtered_data %>%
filter(
tolower(filtered_data$journal) %in% tolower(abdc$journal) # Converting to lower case to ensure that case mismatches do not case issues in matching
)
write.csv(ret_int_abdc, "ret_int_abdc.csv") # This is so that Pari can see the data
There are 951 data points with the conference articles, and 883
without the conference and other types of articles. It is these 883
articles that we focus our attention on.
Let’s just describe this dataset. This is for us to mention in the
introduction section
# Select the specified columns
our_interest <- select(ret_int_abdc, record_id, subject, title, original_paper_date, reason, author)
Plot Average Number of Subjects per Paper Over Time, and the number
of retracted artciles in the ABDC
# Calculate the number of subjects per record
our_interest$subject_count <- sapply(strsplit(our_interest$subject, ";"), function(x) sum(nzchar(x)))
# Extract the year from the original paper date
our_interest$year <- format(our_interest$original_paper_date, "%Y")
# Ensure year is treated as a continuous variable
our_interest$year <- as.numeric(our_interest$year)
# Create a summary data frame
yearly_summary <- our_interest %>%
group_by(year) %>%
summarize(
record_count = n(),
avg_subject_count = mean(subject_count, na.rm = TRUE)
) %>%
ungroup()
# Ensure we have a row for every year in the range from 2000 to 2022
yearly_summary <- data.frame(year = 1995:2022) %>%
left_join(yearly_summary, by = "year") %>%
replace_na(list(record_count = 0, avg_subject_count = 0))
# Find the maximums for scaling the secondary axis
max_records <- max(yearly_summary$record_count)
max_avg_subjects <- max(yearly_summary$avg_subject_count)
# Create the line plot with two y-axes and colored axis labels
ggplot(yearly_summary, aes(x = year)) +
geom_line(aes(y = record_count), color = "blue") +
labs(x = "Year", y = "Number of Records", title = "Number of Records and Average Number of Subjects per Paper over time") +
theme_minimal() +
theme(axis.title.y = element_text(color = "blue")) +
scale_y_continuous(
"Number of Records",
sec.axis = sec_axis(~ . * max_avg_subjects / max_records, name = "Average Number of Subjects", labels = scales::comma)
) +
geom_line(aes(y = avg_subject_count * max_records / max_avg_subjects), color = "red", linetype = "dashed") +
theme(axis.title.y.right = element_text(color = "red"))

This chart shows us that from the turn of the century, the idea of
inter disciplinary research (defined as research being carried out in
multiple subjects within the same meta subject) has increased from just
over 1 to nearly 3. This is a massive shift - and somewhat
concerning.
Checking if the same trend also appears in the metasubject
realm
# Define the mapping of codes to metasubjects
metasubjects_map <- c(
"B/T" = "Business and Technology",
"BLS" = "Basic Life Sciences",
"ENV" = "Environmental Sciences",
"HSC" = "Health Sciences",
"HUM" = "Humanities",
"PHY" = "Physical Sciences",
"SOC" = "Social Sciences"
)
# Extract and map metasubjects
our_interest <- our_interest %>%
mutate(
year = as.numeric(format(original_paper_date, "%Y")),
metasubject_codes = str_extract_all(subject, "\\(\\w+/\\w+\\)|\\(\\w+\\)"),
metasubjects = lapply(metasubject_codes, function(codes) {
unique_codes <- unique(codes)
sapply(unique_codes, function(code) metasubjects_map[substr(code, 2, nchar(code) - 1)])
}),
metasubject_count = sapply(metasubjects, length)
)
# Create a summary data frame for metasubjects
yearly_metasubject_summary <- our_interest %>%
group_by(year) %>%
summarize(
avg_metasubject_count = mean(metasubject_count, na.rm = TRUE),
record_count = n() # Assuming you want to also plot the number of records
) %>%
ungroup()
# Ensure we have a row for every year in the range
yearly_metasubject_summary <- data.frame(year = 1995:2022) %>%
left_join(yearly_metasubject_summary, by = "year") %>%
replace_na(list(avg_metasubject_count = 0, record_count = 0))
# Find the maximum value to set as the upper limit for both y-axes
max_count <- max(yearly_metasubject_summary$record_count, na.rm = TRUE)
max_avg_metasubjects <- max(yearly_metasubject_summary$avg_metasubject_count, na.rm = TRUE)
common_limit <- max(max_count, max_avg_metasubjects)
# Find the maximum value to use as the upper limit for the secondary y-axis
max_records <- max(yearly_metasubject_summary$record_count, na.rm = TRUE)
max_avg_metasubjects <- max(yearly_metasubject_summary$avg_metasubject_count, na.rm = TRUE)
# Create the line plot with adjusted axis scales
ggplot(yearly_metasubject_summary, aes(x = year)) +
geom_line(aes(y = record_count), color = "blue") + # Plot number of records in blue
labs(x = "Year", y = "Number of Records", title = "Number of Records and Average Number of Disciplines per Paper over time") +
theme_minimal() +
theme(
axis.title.y = element_text(color = "blue"),
axis.title.y.right = element_text(color = "red")
) +
scale_y_continuous(
name = "Number of Records",
limits = c(0, max_records), # Set limits for the primary y-axis
sec.axis = sec_axis(~ . * max_avg_metasubjects / max_records, name = "Average Number of Disciplines", labels = scales::comma)
) +
geom_line(aes(y = avg_metasubject_count * max_records / max_avg_metasubjects), color = "red", linetype = "dotted") + # Plot avg metasubjects in red
scale_x_continuous(limits = c(1995, 2022)) # Set x-axis limits from 1980 to 2022

The trend here also appears somewhat consistent with the subjects.
This means that retracted papers are slowly becoming inter disciplinary
in nature.
Now, ww create a correlation plot to see which Disciplines keep
occuring together. I am not doing the regular subjects becasue that
would be too cluttered in my opinion.
# Extract meta-subjects from the 'subject' column
our_interest$meta_subjects <- str_extract_all(our_interest$subject, "\\(.*?\\)")
# Create a unique list of all meta-subjects
all_meta_subjects <- unique(unlist(our_interest$meta_subjects))
# Function to create dummy variables
create_dummy <- function(meta_subjects, subject) {
as.integer(subject %in% meta_subjects)
}
# Apply the function to create dummy variables for each meta-subject
for (meta_subject in all_meta_subjects) {
our_interest[[meta_subject]] <- sapply(our_interest$meta_subjects, create_dummy, subject = meta_subject)
}
# Select only the meta-subject dummy variables
meta_subject_cols <- all_meta_subjects
# Calculate the correlation matrix
cor_matrix <- cor(our_interest[, meta_subject_cols], use = "complete.obs")
# Melt the correlation matrix for visualization
melted_cor_matrix <- melt(cor_matrix)
# Plot the correlation matrix
ggplot(data = melted_cor_matrix, aes(x = Var1, y = Var2, fill = value)) +
geom_tile() +
geom_text(aes(label = round(value, 2)), color = "black", size = 3) +
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0, limit = c(-1, 1), space = "Lab",
name = "Pearson\nCorrelation") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
axis.title = element_blank()) + ggtitle("Inter Discipline Correlation Comparison")

This is the key for the reference of others: (B/T): Business and
Technology (BLS): Basic Life Sciences (ENV): Environmental Sciences
(HSC): Health Sciences (HUM):Humanities (PHY): Physical Sciences (SOC):
Social Sciences
This investigation reveals that there are no two subjects that are
strongly correlated. However, we can try something interesting here.
library(dplyr)
library(ggplot2)
library(stringr)
library(reshape2)
library(gridExtra) # This library is used to arrange ggplots side by side
# Extract meta-subjects from the 'subject' column
our_interest$meta_subjects <- str_extract_all(our_interest$subject, "\\(.*?\\)")
# Create a unique list of all meta-subjects
all_meta_subjects <- unique(unlist(our_interest$meta_subjects))
# Function to create dummy variables
create_dummy <- function(meta_subjects, subject) {
as.integer(subject %in% meta_subjects)
}
# Apply the function to create dummy variables for each meta-subject
for (meta_subject in all_meta_subjects) {
our_interest[[meta_subject]] <- sapply(our_interest$meta_subjects, create_dummy, subject = meta_subject)
}
# Filter data for the two periods
data_until_2010 <- our_interest %>% filter(year <= 2010)
data_after_2010 <- our_interest %>% filter(year > 2010)
# Select only the meta-subject dummy variables for correlation calculation
meta_subject_cols <- all_meta_subjects
# Calculate the correlation matrix for both periods
cor_matrix_until_2010 <- cor(data_until_2010[, meta_subject_cols], use = "complete.obs")
cor_matrix_after_2010 <- cor(data_after_2010[, meta_subject_cols], use = "complete.obs")
# Melt the correlation matrices for visualization
melted_cor_matrix_until_2010 <- melt(cor_matrix_until_2010)
melted_cor_matrix_after_2010 <- melt(cor_matrix_after_2010)
# Function to create a ggplot of the correlation matrix
create_cor_plot <- function(melted_cor_matrix) {
ggplot(data = melted_cor_matrix, aes(x = Var1, y = Var2, fill = value)) +
geom_tile() +
geom_text(aes(label = round(value, 2)), color = "black", size = 3) +
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0, limits = c(-1, 1), space = "Lab",
name = "Pearson\nCorrelation") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
axis.title = element_blank())
}
# Create the plots
plot_until_2010 <- create_cor_plot(melted_cor_matrix_until_2010)
plot_after_2010 <- create_cor_plot(melted_cor_matrix_after_2010)
library(gridExtra)
# Add individual titles to each plot
plot_until_2010 <- plot_until_2010 + ggtitle("Correlation Until 2010") + theme(plot.title = element_text(hjust = 0.5))
plot_after_2010 <- plot_after_2010 + ggtitle("Correlation After 2010") + theme(plot.title = element_text(hjust = 0.5))
# Combine the plots side by side with a common title
grid.arrange(plot_until_2010, plot_after_2010, ncol = 2,
top = textGrob("Inter Discipline Correlation Comparison", gp = gpar(fontface = "bold", fontsize = 14)))

NA
NA
This shows that there has not really been any significant trend. If
anything, the correlation has dropped over time.
This points to the fact that there this issue is not particularly
limited to some areas - but much more rampant.
In fact, if we start looking at the titles of the papers, we begin to
get a much better picture.
Create a Word Map from the ‘Title’ Variable
library(wordcloud)
Loading required package: RColorBrewer
library(tm)
Loading required package: NLP
Attaching package: ‘NLP’
The following object is masked from ‘package:httr’:
content
The following object is masked from ‘package:ggplot2’:
annotate
# Create a text corpus
corpus = Corpus(VectorSource(our_interest$title))
# Clean up the text
corpus = tm_map(corpus, content_transformer(tolower))
Warning: transformation drops documents
corpus = tm_map(corpus, removePunctuation)
Warning: transformation drops documents
corpus = tm_map(corpus, removeNumbers)
Warning: transformation drops documents
corpus = tm_map(corpus, removeWords, stopwords("english"))
Warning: transformation drops documents
# Create a word cloud
wordcloud(corpus, max.words = 100)

Well, we have to speak about this team!
Let me just find out if there is some correlation between the reasons
that are cited for retraction
# Step 1: Split the 'reason' field into individual reasons and remove the '+' prefix
reasons_list <- strsplit(gsub("^\\+", "", our_interest$reason), ";")
# Step 2: Identify unique reasons
unique_reasons <- unique(unlist(reasons_list))
# Step 3: Create dummy variables for each unique reason
for(reason in unique_reasons) {
our_interest[[reason]] <- sapply(reasons_list, function(x) as.integer(reason %in% x))
}
# Select only dummy variables (and any other numeric variables you want to include)
numeric_data <- our_interest[, sapply(our_interest, is.numeric)]
# Compute the correlation matrix for numeric data
cor_matrix <- cor(numeric_data)
# Melt the correlation matrix for visualization
melted_cor_matrix <- reshape2::melt(cor_matrix)
# Define a threshold for displaying text
threshold <- 0.5
# Plot the correlation matrix
ggplot(data = melted_cor_matrix, aes(x=Var1, y=Var2, fill=value)) +
geom_tile() +
geom_text(aes(label = ifelse(abs(value) > threshold, round(value, 2), '')), color = "black", size = 2.5) +
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0, limit = c(-1,1), space = "Lab",
name="Pearson\nCorrelation") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 4),
axis.text.y = element_text(size = 6),
axis.title = element_blank()) +
coord_fixed() # Ensure square cells

This looks a little difficult to comprehend.I am going to map them to
something more easy to understand and check again.
Creating broader themes.
# Define the patterns for each category
patterns <- list(
Intellectual_Property_Violations = c("Plagiarism", "Duplication", "Euphemisms for Plagiarism", "False/Forged Authorship"),
Research_Integrity_and_Quality_Issues = c("Not Reproducible", "Unreliable Results", "Error in Text", "Error in Analyses", "Error in Methods", "Error in Data", "Error in Results", "Fabrication", "Falsification", "Ethical Violations", "Issues About Data"),
Peer_Review_and_Editorial_Concerns = c("Fake Peer Review", "Rogue Editor", "Investigation by Journal/Publisher", "Error by Journal/Publisher", "Objections by Author"),
Policy_and_Legal_Concerns = c("Breach of Policy", "Issues about Referencing", "Legal Reasons", "Lack of Approval"),
Publication_and_Communication_Issues = c("Withdrawal", "Limited or No Information", "Notice - Lack of", "Author Unresponsive", "Update of Prior Notice"),
Investigations_and_Actions = c("Investigation by Third Party", "Doing the Right Thing"),
Miscellaneous_Issues = c("Date of Retraction", "Randomly Generated Content", "Original Data not Provided", "Concerns About Image")
)
# Function to create dummy variables for categories based on the presence of certain patterns
create_dummy_vars <- function(df, patterns) {
for (category in names(patterns)) {
pattern <- patterns[[category]]
df[[category]] <- as.integer(sapply(df$reason, function(x) {
any(sapply(pattern, function(y) str_detect(x, regex(y, ignore_case = TRUE))))
}))
}
return(df)
}
# Apply the function to the data frame
our_interest <- create_dummy_vars(our_interest, patterns)
# Ensure these columns exist in your our_interest dataframe
selected_columns <- c("Intellectual_Property_Violations", "Research_Integrity_and_Quality_Issues",
"Peer_Review_and_Editorial_Concerns", "Policy_and_Legal_Concerns",
"Publication_and_Communication_Issues", "Investigations_and_Actions",
"Miscellaneous_Issues")
# Check if all selected columns are present in our_interest
if(all(selected_columns %in% names(our_interest))) {
# Select only the specified dummy variable columns
dummy_data <- our_interest[, selected_columns]
# Calculate the correlation matrix
cor_matrix <- cor(dummy_data, use = "complete.obs") # use complete.obs to handle NA values
# Melt the correlation matrix for visualization
melted_cor_matrix <- reshape2::melt(cor_matrix)
# Plot the correlation matrix with numbers
ggplot(data = melted_cor_matrix, aes(x=Var1, y=Var2, fill=value)) +
geom_tile() +
geom_text(aes(label = round(value, 2)), color = "black", size = 3) +
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0, limit = c(-1,1), space = "Lab",
name="Pearson\nCorrelation") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
axis.title = element_blank())
} else {
stop("Not all specified columns exist in the dataframe.")
}

Here are my key observations in this:
- It looks like Investigations and Misc issues keep co-occuring
- Policy and legal concerns seem to do so too.
- Investigations seem to follow the Peer review concerns.
- Investigations also seem to follow Research integrity issues.
Now this begs the question, is there something different that’s going
on in the general set of papers?
Let me just check that out here
#trying to find out if there are correlations in the broader dataset
of all retractions.
# Define the patterns for each category
patterns <- list(
Intellectual_Property_Violations = c("Plagiarism", "Duplication", "Euphemisms for Plagiarism", "False/Forged Authorship"),
Research_Integrity_and_Quality_Issues = c("Not Reproducible", "Unreliable Results", "Error in Text", "Error in Analyses", "Error in Methods", "Error in Data", "Error in Results", "Fabrication", "Falsification", "Ethical Violations", "Issues About Data"),
Peer_Review_and_Editorial_Concerns = c("Fake Peer Review", "Rogue Editor", "Investigation by Journal/Publisher", "Error by Journal/Publisher", "Objections by Author"),
Policy_and_Legal_Concerns = c("Breach of Policy", "Issues about Referencing", "Legal Reasons", "Lack of Approval"),
Publication_and_Communication_Issues = c("Withdrawal", "Limited or No Information", "Notice - Lack of", "Author Unresponsive", "Update of Prior Notice"),
Investigations_and_Actions = c("Investigation by Third Party", "Doing the Right Thing"),
Miscellaneous_Issues = c("Date of Retraction", "Randomly Generated Content", "Original Data not Provided", "Concerns About Image")
)
# Function to create dummy variables for categories based on the presence of certain patterns
create_dummy_vars <- function(df, patterns) {
for (category in names(patterns)) {
pattern <- patterns[[category]]
df[[category]] <- as.integer(sapply(df$reason, function(x) {
any(sapply(pattern, function(y) str_detect(x, regex(y, ignore_case = TRUE))))
}))
}
return(df)
}
our_interest_temp<- our_interest
# Apply the function to the data frame
our_interest <- create_dummy_vars(data, patterns)
# Ensure these columns exist in your our_interest dataframe
selected_columns <- c("Intellectual_Property_Violations", "Research_Integrity_and_Quality_Issues",
"Peer_Review_and_Editorial_Concerns", "Policy_and_Legal_Concerns",
"Publication_and_Communication_Issues", "Investigations_and_Actions",
"Miscellaneous_Issues")
# Check if all selected columns are present in our_interest
if(all(selected_columns %in% names(our_interest))) {
# Select only the specified dummy variable columns
dummy_data <- our_interest[, selected_columns]
# Calculate the correlation matrix
cor_matrix <- cor(dummy_data, use = "complete.obs") # use complete.obs to handle NA values
# Melt the correlation matrix for visualization
melted_cor_matrix <- reshape2::melt(cor_matrix)
# Plot the correlation matrix with numbers
ggplot(data = melted_cor_matrix, aes(x=Var1, y=Var2, fill=value)) +
geom_tile() +
geom_text(aes(label = round(value, 2)), color = "black", size = 3) +
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0, limit = c(-1,1), space = "Lab",
name="Pearson\nCorrelation") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
axis.title = element_blank())
} else {
stop("Not all specified columns exist in the dataframe.")
}

our_interest<- our_interest_temp
This presents the an interesting question. Are there two different
stories here?
COntrasting management with other, non managmenet fields. Creating
two separate subsets now - one for business related, and one for non
business
# Define business-related subjects
business_subjects <- c("Business - Management",
"Business - Economics",
"Business - Marketing",
"Business - General",
"Business - Manufacturing",
"Business - Accounting")
# Create a single pattern string for matching
pattern <- paste(business_subjects, collapse = "|")
# This is the Business related subjects
data_business <- data %>%
filter(str_detect(subject, pattern))
# This is the Non Business related subjects
data_nonbusiness <- data %>%
filter(!str_detect(subject, pattern))
data_temp<- data
Trying to plot how retractions have been in Non Management
disciplines
# Prepare data
yearly_data <- data_nonbusiness %>%
group_by(retraction_year) %>%
summarize(average_duration = mean(duration_in_months, na.rm = TRUE),
retraction_count = n())
# Normalize the RetractionCount for better visualization
max_duration <- max(yearly_data$average_duration, na.rm = TRUE)
max_count <- max(yearly_data$retraction_count, na.rm = TRUE)
yearly_data$NormalizedCount <- yearly_data$retraction_count / max_count * max_duration
retractions_nonmanagement<- ggplot(yearly_data, aes(x = retraction_year)) +
geom_line(aes(y = average_duration, group = 1), color = "blue") +
geom_point(aes(y = average_duration), color = "blue") +
geom_bar(aes(y = NormalizedCount), stat = "identity", fill = "red", alpha = 0.5) +
scale_x_continuous(limits = c(1990, NA)) + # Limiting x-axis to start from 1970+
scale_y_continuous(name = "Average Duration in Months",
sec.axis = sec_axis(~ . * max_count / max_duration,
name = "Number of Retractions")) +
labs(title = "Retractions over the Years: Duration and Count (Non Management Disciplines)",
x = "Retraction Year") +
theme_minimal()
Trying to plot how retractions have been in Management
disciplines
# Prepare data
yearly_data <- data_business %>%
group_by(retraction_year) %>%
summarize(average_duration = mean(duration_in_months, na.rm = TRUE),
retraction_count = n())
# Normalize the RetractionCount for better visualization
max_duration <- max(yearly_data$average_duration, na.rm = TRUE)
max_count <- max(yearly_data$retraction_count, na.rm = TRUE)
yearly_data$NormalizedCount <- yearly_data$retraction_count / max_count * max_duration
retractions_management<- ggplot(yearly_data, aes(x = retraction_year)) +
geom_line(aes(y = average_duration, group = 1), color = "blue") +
geom_point(aes(y = average_duration), color = "blue") +
geom_bar(aes(y = NormalizedCount), stat = "identity", fill = "red", alpha = 0.5) +
scale_x_continuous(limits = c(1990, NA)) + # Limiting x-axis to start from 1970+
scale_y_continuous(name = "Average Duration in Months",
sec.axis = sec_axis(~ . * max_count / max_duration,
name = "Number of Retractions")) +
labs(title = "Retractions over the Years: Duration and Count (Management Disciplines)",
x = "Retraction Year") +
theme_minimal()
Displaying the plot
grid.arrange(retractions_management, retractions_nonmanagement, ncol = 1)

Trying to understand the distribution of subjects now.
Distribution of Subjects - Non Management Subjects
# Separate the subjects into individual rows
data_subjects <- data_nonbusiness %>%
separate_rows(subject, sep = ";\\s*")
# Count the occurrences of each subject
subject_count <- data_subjects %>%
count(subject, sort = TRUE)
# Create a horizontal bar chart
ggplot(subject_count, aes(y = reorder(subject, n), x = n)) +
geom_bar(stat = "identity", position = "dodge") +
theme(axis.text.y = element_text(size = 4)) +
labs(y = "Subject", x = "Count", title = "Distribution of Subjects - Non Management")

# Rename the subject to the broader theme that's written in the brackets
subject_count <- subject_count %>%
mutate(subject = str_match(subject, "\\(([^)]+)\\)")[,2])
# Remove NA values that might have been introduced if there were subjects without brackets
subject_count <- subject_count %>%
filter(!is.na(subject))
# Create a horizontal bar chart
ggplot(subject_count, aes(y = reorder(subject, n), x = n)) +
geom_bar(stat = "identity", position = "dodge") +
theme(axis.text.y = element_text(size = 6)) +
labs(y = "Subject", x = "Count", title = "Distribution of Subjects - Non Management Subjects")

Distribution of Subjects - Management Subjects
# Separate the subjects into individual rows
data_subjects <- data_business %>%
separate_rows(subject, sep = ";\\s*")
# Count the occurrences of each subject
subject_count <- data_subjects %>%
count(subject, sort = TRUE)
# Create a horizontal bar chart
ggplot(subject_count, aes(y = reorder(subject, n), x = n)) +
geom_bar(stat = "identity", position = "dodge") +
theme(axis.text.y = element_text(size = 4)) +
labs(y = "Subject", x = "Count", title = "Distribution of Subjects - Management")

# Rename the subject to the broader theme that's written in the brackets
subject_count <- subject_count %>%
mutate(subject = str_match(subject, "\\(([^)]+)\\)")[,2])
# Remove NA values that might have been introduced if there were subjects without brackets
subject_count <- subject_count %>%
filter(!is.na(subject))
# Create a horizontal bar chart
ggplot(subject_count, aes(y = reorder(subject, n), x = n)) +
geom_bar(stat = "identity", position = "dodge") +
theme(axis.text.y = element_text(size = 6)) +
labs(y = "Subject", x = "Count", title = "Distribution of Subjects")

Note: You see that there are other non management areas also linked
here. That’s because a lot of the papers have also been listed as
science, environment and sociology, etc.
Trying to understand the distribution of countries now
# Separate the subjects into individual rows
data_country <- data_nonbusiness %>%
separate_rows(country, sep = ";\\s*")
# Count the occurrences of each subject
country_count <- data_country %>%
count(country, sort = TRUE)
# Create a horizontal bar chart
ggplot(country_count, aes(y = reorder(country, n), x = n)) +
geom_bar(stat = "identity", position = "dodge") +
theme(axis.text.y = element_text(size = 4)) +
labs(y = "Country", x = "Count", title = "Distribution of Countries - Non Management")

length(unique(country_count$country))
[1] 173
There appear to be authors from 173 countries participating here.
# Separate the subjects into individual rows
data_country <- data_business %>%
separate_rows(country, sep = ";\\s*")
# Count the occurrences of each subject
country_count <- data_country %>%
count(country, sort = TRUE)
# Create a horizontal bar chart
ggplot(country_count, aes(y = reorder(country, n), x = n)) +
geom_bar(stat = "identity", position = "dodge") +
theme(axis.text.y = element_text(size = 4)) +
labs(y = "Country", x = "Count", title = "Distribution of Countries - Non Management")

NA
NA
length(unique(country_count$country))
[1] 94
There appear to be authors from 94 countries participating here.
Trying to understand the distribution of institutions now
# Separate the subjects into individual rows
data_institution <- data_nonbusiness %>%
separate_rows(institution, sep = ";\\s*")
# Count the occurrences of each subject
institution_count <- data_institution %>%
count(institution, sort = TRUE)
length(unique(institution_count$institution))
[1] 77610
There appear to be authors from 77610 institutions participated
here.
# Separate the subjects into individual rows
data_institution <- data_business %>%
separate_rows(institution, sep = ";\\s*")
# Count the occurrences of each subject
institution_count <- data_institution %>%
count(institution, sort = TRUE)
length(unique(institution_count$institution))
[1] 8240
There appear to be authors from 8240 institutions participated
here.
Checking on repeat offenders
# Separate the subjects into individual rows
data_author <- data_nonbusiness %>%
separate_rows(author, sep = ";\\s*")
# Count the occurrences of each subject
author_count <- data_author %>%
count(author, sort = TRUE)
author_count_nonbusiness <-author_count
length(unique(author_count$author))
[1] 122573
There are about 1,22,573 unique authors in the non business
dataset.
length(unique(author_count$author))/length(data_nonbusiness$record_id)
[1] 2.850535
There have on average been, 2.85 authors per paper.
length(unique(author_count$author))/length(data_nonbusiness$record_id)
[1] 2.850535
# Step 1: Add a column with the number of authors per publication
data_nonbusiness <- data_nonbusiness %>%
mutate(
num_authors = sapply(strsplit(as.character(author), ";"), length),
publication_year = year(original_paper_date)
)
# Step 2: Group by publication year and calculate the average number of authors
average_authors_per_year <- data_nonbusiness %>%
group_by(publication_year) %>%
summarise(average_authors = mean(num_authors, na.rm = TRUE))
# Plotting the average number of authors per year
ggplot(average_authors_per_year, aes(x = publication_year, y = average_authors)) +
geom_line() + # Line plot
geom_point() + # Adding points to each year
theme_minimal() +
labs(
title = "Average Number of Authors per Publication Over Years",
x = "Publication Year",
y = "Average Number of Authors"
) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1) # Adjusting x-axis labels for better readability
)+
scale_x_continuous(limits = c(1990, max(average_authors_per_year$publication_year))) # Limiting x-axis from 1980 onward

NA
NA
# Step 1: Add a column with the number of authors per publication
data_business <- data_business %>%
mutate(
num_authors = sapply(strsplit(as.character(author), ";"), length),
publication_year = year(original_paper_date)
)
# Step 2: Group by publication year and calculate the average number of authors
average_authors_per_year <- data_business %>%
group_by(publication_year) %>%
summarise(average_authors = mean(num_authors, na.rm = TRUE))
# Plotting the average number of authors per year
ggplot(average_authors_per_year, aes(x = publication_year, y = average_authors)) +
geom_line() + # Line plot
geom_point() + # Adding points to each year
theme_minimal() +
labs(
title = "Average Number of Authors per Publication Over Years",
x = "Publication Year",
y = "Average Number of Authors"
) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1) # Adjusting x-axis labels for better readability
)+
scale_x_continuous(limits = c(1990, max(average_authors_per_year$publication_year))) # Limiting x-axis from 1980 onward

NA
NA
Preparing a joint plot
# Prepare nonbusiness data
data_nonbusiness <- data_nonbusiness %>%
mutate(
num_authors = sapply(strsplit(as.character(author), ";"), length),
publication_year = year(original_paper_date),
type = "Nonbusiness"
)
# Prepare business data
data_business <- data_business %>%
mutate(
num_authors = sapply(strsplit(as.character(author), ";"), length),
publication_year = year(original_paper_date),
type = "Business"
)
# Combine the datasets
combined_data <- bind_rows(data_nonbusiness, data_business)
# Group by publication year and type, then calculate the average number of authors
average_authors_per_year_type <- combined_data %>%
group_by(publication_year, type) %>%
summarise(average_authors = mean(num_authors, na.rm = TRUE))
`summarise()` has grouped output by 'publication_year'. You can override using the `.groups` argument.
# Plotting the average number of authors per year for both types
ggplot(average_authors_per_year_type, aes(x = publication_year, y = average_authors, color = type)) +
geom_line() + # Line plot
geom_point() + # Adding points to each year
theme_minimal() +
labs(
title = "Average Number of Authors per Retracted Publication Over Years",
x = "Publication Year",
y = "Average Number of Authors"
) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1) # Adjusting x-axis labels for better readability
)+
scale_x_continuous(limits = c(1990, max(average_authors_per_year_type$publication_year))) #

From this, it does look like management related publications (as
classified by the authors) does not seem to have as many authors as non
management related articles.
# Prepare data
yearly_data <- ret_int_abdc %>%
group_by(retraction_year) %>%
summarize(average_duration = mean(duration_in_months, na.rm = TRUE),
retraction_count = n())
# Normalize the RetractionCount for better visualization
max_duration <- max(yearly_data$average_duration, na.rm = TRUE)
max_count <- max(yearly_data$retraction_count, na.rm = TRUE)
yearly_data$NormalizedCount <- yearly_data$retraction_count / max_count * max_duration
retractions_management<- ggplot(yearly_data, aes(x = retraction_year)) +
geom_line(aes(y = average_duration, group = 1), color = "blue") +
geom_point(aes(y = average_duration), color = "blue") +
geom_bar(aes(y = NormalizedCount), stat = "identity", fill = "red", alpha = 0.5) +
scale_x_continuous(limits = c(2000, NA)) +
scale_y_continuous(name = "Average Duration in Months",
sec.axis = sec_axis(~ . * max_count / max_duration,
name = "Number of Retractions")) +
labs(title = "Retractions over the Years: Duration and Count (ABDC)",
x = "Retraction Year") +
theme(
plot.title = element_text(hjust = 0.5), # Center-align the title
plot.subtitle = element_text(hjust = 0.5), # Center-align the subtitle if you have one
axis.title.x = element_text(hjust = 0.5) # Center-align the x-axis label
)
retractions_management

From this data set, let’s try to pull out the names of every author..
and see if there are 1. repeat offenders 2. How many total authors are
there with retraction related issues
# Expand the dataset so each row represents a record-author combination
expanded_dataset <- ret_int_abdc %>%
separate_rows(author, sep = ";") %>%
mutate(author = trimws(author)) # Remove any leading/trailing whitespace
# Count the number of retractions for each author
author_retraction_counts <- expanded_dataset %>%
group_by(author) %>%
summarise(retraction_count = n()) %>%
filter(author != "") # Remove empty author entries if any
# Define a threshold for the maximum number of retractions per author
threshold = 10 # Adjust this number based on your data and needs
# Filter the data to exclude outliers
filtered_author_retraction_counts <- author_retraction_counts %>%
filter(retraction_count <= threshold)
ggplot(filtered_author_retraction_counts, aes(x = retraction_count)) +
geom_histogram(binwidth = 1, fill = "blue", color = "black") +
labs(title = paste("Distribution of Retractions per Author (Limited to", threshold, "Retractions)"),
x = "Number of Retractions",
y = "Count of Authors") +
theme_minimal()

It looks like serial retractions are not very commonplace. There are
hardly 200 authors among 2229 who have multiple counts of
retraction.
Let’s try to create an author author relationship network.
But that’s not possible to do with the limited data that we have
access to at the moment. We are going to have to explore who all the
authors have linked up with in the past aswell.
One of the issues that becomes increasingly apparent is the
nationality of the retractions. It appears that many of the retractions
stem from nations like China.
Let me show you.
# Ensure the 'country' column is a character vector if it is not already
our_interest <- ret_int_abdc %>%
mutate(country = as.character(country))
# Assuming 'country' is a column where countries are separated by semicolons (and possibly followed by spaces)
data_country <- our_interest %>%
separate_rows(country, sep = ";\\s*") # sep regex matches a semicolon followed by any number of spaces
# Count the occurrences of each country
country_count <- data_country %>%
count(country, sort = TRUE)
# Create a horizontal bar chart
ggplot(country_count, aes(x = reorder(country, n), y = n)) +
geom_bar(stat = "identity") +
coord_flip() + # Flip the coordinates to make the bars horizontal
theme(axis.text.x = element_text(size = 12),axis.text.y = element_text(size = 6)) + # Adjust the size if needed
labs(x = "Country", y = "Count", title = "Distribution of Countries")

it looks like China, US, UK, Netherlands and India are the key
sources of retractions.
Can in be that this is a problem is located to within certain
countries? or is this a truly corss cultural issue?
Let’s try and doing a QAP correlation to find out.
Creating retraction-author-author network
# Create a data frame where each row represents a single author for a given record_id
author_records <- our_interest %>%
separate_rows(author, sep = ";") %>%
distinct(record_id, author)
# Create a square matrix of authors, initialized to zero
unique_authors <- sort(unique(author_records$author))
coauthor_retraction_matrix <- matrix(0, nrow = length(unique_authors), ncol = length(unique_authors),
dimnames = list(unique_authors, unique_authors))
# Fill the matrix with 1's where authors share a record_id
for (i in seq_len(nrow(author_records))) {
for (j in seq_len(nrow(author_records))) {
if (author_records$record_id[i] == author_records$record_id[j]) {
coauthor_retraction_matrix[author_records$author[i], author_records$author[j]] <- 1
}
}
}
# Remove self-loops if desired (authors compared with themselves)
diag(coauthor_retraction_matrix) <- 0
Now we have a dataset which has all the retraction author’s
retraction network.. But then, this is only the retracted papers, and
not the rest of all the papers that they have worked on.
Building another matrix - this time to talk about the countries the
authors are from.
# Splitting the author field as there could be multiple authors per record
author_country <- our_interest %>%
separate_rows(author, sep = ";") %>%
distinct(record_id, author, country)
# Creating a list of unique authors
unique_authors <- sort(unique(author_country$author))
# Creating an empty matrix to store the connections
author_country_matrix <- matrix(0, nrow = length(unique_authors), ncol = length(unique_authors))
rownames(author_country_matrix) <- unique_authors
colnames(author_country_matrix) <- unique_authors
# Filling the matrix
for (i in 1:length(unique_authors)) {
for (j in 1:length(unique_authors)) {
if (i != j) {
# Check if authors i and j are associated with the same country
common_countries <- intersect(author_country$country[author_country$author == unique_authors[i]],
author_country$country[author_country$author == unique_authors[j]])
if (length(common_countries) > 0) {
author_country_matrix[i, j] <- 1
author_country_matrix[j, i] <- 1 # Matrix is symmetric
}
}
}
}
diag(author_country_matrix) <- 0
Trying to use asnipe and vegan together to run a QAP correlation.
library(asnipe)
library(vegan)
qap_result <- mantel(coauthor_retraction_matrix, author_country_matrix, permutations = 1000)
print(qap_result)
Mantel statistic based on Pearson's product-moment correlation
Call:
mantel(xdis = coauthor_retraction_matrix, ydis = author_country_matrix, permutations = 1000)
Mantel statistic r: 0.1181
Significance: 0.000999
Upper quantiles of permutations (null model):
90% 95% 97.5% 99%
0.00134 0.00178 0.00199 0.00248
Permutation: free
Number of permutations: 1000
This test suggests that there is a statistically significant, though
relatively weak, positive correlation between the coauthor retraction
matrix and the author country matrix. This means that there is some
level of association between the patterns or relationships represented
by the country relationship matrix and the retraction relationship
matrix.
This is interesting..
Now, maybe there is a stronger relationship to detect if we check the
institute level relations.
Creating an instituion relationship matrix.
# Splitting the author field as there could be multiple authors per record
author_institution <- our_interest %>%
separate_rows(author, sep = ";") %>%
distinct(record_id, author, institution)
# Creating a list of unique authors
unique_authors <- sort(unique(author_institution$author))
# Creating an empty matrix to store the connections
author_institution_matrix <- matrix(0, nrow = length(unique_authors), ncol = length(unique_authors))
rownames(author_institution_matrix) <- unique_authors
colnames(author_institution_matrix) <- unique_authors
# Filling the matrix
for (i in 1:length(unique_authors)) {
for (j in 1:length(unique_authors)) {
if (i != j) {
# Check if authors i and j are associated with the same institution
common_countries <- intersect(author_institution$institution[author_institution$author == unique_authors[i]],
author_institution$institution[author_institution$author == unique_authors[j]])
if (length(common_countries) > 0) {
author_institution_matrix[i, j] <- 1
author_institution_matrix[j, i] <- 1 # Matrix is symmetric
}
}
}
}
Once again, Trying to run a QAP correlation.
qap_result <- mantel(coauthor_retraction_matrix, author_institution_matrix, permutations = 1000)
print(qap_result)
Mantel statistic based on Pearson's product-moment correlation
Call:
mantel(xdis = coauthor_retraction_matrix, ydis = author_institution_matrix, permutations = 1000)
Mantel statistic r: 0.9866
Significance: 0.000999
Upper quantiles of permutations (null model):
90% 95% 97.5% 99%
0.00109 0.00149 0.00189 0.00229
Permutation: free
Number of permutations: 1000
This suggests a very strong positive correlation between the
coauthor_retraction_matrix and the author_institution_matrix. The
extremely low p-value indicates that this correlation is highly unlikely
to have occurred by chance. This implies a significant association
between the patterns or relationships represented in these two matrices,
suggesting that the coauthorship retraction patterns are closely related
to the institutions of the authors.
I think we are doing something wrong in this approach. The matrices
are correlated because of how the data was sourced. I wonder why there
was not a 1.00 correlation.
Creating author-publisher network
# Splitting the author field as there could be multiple authors per record
author_split <- expanded_dataset %>%
separate_rows(author, sep = ";") %>%
distinct(record_id, author, publisher)
# Creating a list of unique authors
unique_authors <- sort(unique(author_split$author))
# Creating an empty matrix to store the connections
author_publisher_matrix <- matrix(0, nrow = length(unique_authors), ncol = length(unique_authors))
rownames(author_publisher_matrix) <- unique_authors
colnames(author_publisher_matrix) <- unique_authors
# Filling the matrix
for (i in 1:length(unique_authors)) {
for (j in 1:length(unique_authors)) {
if (i != j) {
# Check if authors i and j have published with the same publisher
common_publishers <- intersect(author_split$publisher[author_split$author == unique_authors[i]],
author_split$publisher[author_split$author == unique_authors[j]])
if (length(common_publishers) > 0) {
author_publisher_matrix[i, j] <- 1
author_publisher_matrix[j, i] <- 1 # Matrix is symmetric
}
}
}
}
Once again, Trying to run a QAP correlation. This time to see if the
author-publisher relationship has some impact..
qap_result <- mantel(coauthor_retraction_matrix, author_publisher_matrix, permutations = 1000)
print(qap_result)
Mantel statistic based on Pearson's product-moment correlation
Call:
mantel(xdis = coauthor_retraction_matrix, ydis = author_publisher_matrix, permutations = 1000)
Mantel statistic r: 0.09124
Significance: 0.000999
Upper quantiles of permutations (null model):
90% 95% 97.5% 99%
0.00116 0.00152 0.00188 0.00241
Permutation: free
Number of permutations: 1000
The test suggests that there is a statistically significant, albeit
weak, positive correlation between the patterns of coauthorship
retraction and author publisher associations represented in the two
matrices. However, given the low correlation coefficient, the strength
of this association is not very strong.
I’m just trying a few other things here.
Creating author-journal network
# Splitting the author field as there could be multiple authors per record
author_split <- expanded_dataset %>%
separate_rows(author, sep = ";") %>%
distinct(record_id, author, journal)
# Creating a list of unique authors
unique_authors <- sort(unique(author_split$author))
# Creating an empty matrix to store the connections
author_journal_matrix <- matrix(0, nrow = length(unique_authors), ncol = length(unique_authors))
rownames(author_journal_matrix) <- unique_authors
colnames(author_journal_matrix) <- unique_authors
# Filling the matrix
for (i in 1:length(unique_authors)) {
for (j in 1:length(unique_authors)) {
if (i != j) {
# Check if authors i and j have published with the same journal
common_journals <- intersect(author_split$journal[author_split$author == unique_authors[i]],
author_split$journal[author_split$author == unique_authors[j]])
if (length(common_journals) > 0) {
author_journal_matrix[i, j] <- 1
author_journal_matrix[j, i] <- 1 # Matrix is symmetric
}
}
}
}
Once again, Trying to run a QAP correlation. This time to see if the
author-journal relationship has some impact..
qap_result <- mantel(coauthor_retraction_matrix, author_journal_matrix, permutations = 1000)
print(qap_result)
Mantel statistic based on Pearson's product-moment correlation
Call:
mantel(xdis = coauthor_retraction_matrix, ydis = author_journal_matrix, permutations = 1000)
Mantel statistic r: 0.2089
Significance: 0.000999
Upper quantiles of permutations (null model):
90% 95% 97.5% 99%
0.00119 0.00163 0.00190 0.00216
Permutation: free
Number of permutations: 1000
Doing a subject-author relationship
# Splitting the author and subject fields as there could be multiple authors and subjects per record
author_subject_split <- expanded_dataset %>%
separate_rows(author, subject, sep = ";") %>%
distinct(record_id, author, subject)
# Creating a list of unique authors and subjects
unique_authors <- sort(unique(author_subject_split$author))
unique_subjects <- sort(unique(author_subject_split$subject))
# Creating an empty matrix to store the connections
author_subject_matrix <- matrix(0, nrow = length(unique_authors), ncol = length(unique_authors))
rownames(author_subject_matrix) <- unique_authors
colnames(author_subject_matrix) <- unique_authors
# Filling the matrix
for (i in 1:length(unique_authors)) {
for (j in 1:length(unique_authors)) {
if (i != j) {
# Check if authors i and j have published in the same subject
common_subjects <- intersect(author_subject_split$subject[author_subject_split$author == unique_authors[i]],
author_subject_split$subject[author_subject_split$author == unique_authors[j]])
if (length(common_subjects) > 0) {
author_subject_matrix[i, j] <- 1
author_subject_matrix[j, i] <- 1 # Matrix is symmetric
}
}
}
}
qap_result <- mantel(author_subject_matrix, author_journal_matrix, permutations = 1000)
print(qap_result)
LS0tCnRpdGxlOiAiTGlvbiBpbiB0aGUgUm9vbSIKb3V0cHV0OgogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCgoKIyMjIExvYWRpbmcgdGhlIG5lY2Vzc2FyeSBwYWNrYWdlcyBmb3IgdGhlIHByb2plY3QKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkgICMgTG9hZHMgZ2dwbG90MiwgZHBseXIsIHRpZHlyLCByZWFkciwgcHVycnIsIHRpYmJsZSwgYW5kIHN0cmluZ3IKbGlicmFyeShyZWFkeGwpICAgICAjIEZvciByZWFkaW5nIEV4Y2VsIGZpbGVzCmxpYnJhcnkocnZlc3QpICAgICAgIyBGb3Igd2ViIHNjcmFwaW5nCmxpYnJhcnkoaHR0cikgICAgICAgIyBGb3Igd29ya2luZyB3aXRoIEhUVFAKbGlicmFyeShyY3Jvc3NyZWYpICAjIEZvciB1c2luZyBDcm9zc1JlZidzIEFQSQpsaWJyYXJ5KGphbml0b3IpICAgICMgRm9yIGNsZWFuaW5nIGRhdGEKbGlicmFyeShyZXNoYXBlMikgICAjIEZvciByZXNoYXBpbmcgZGF0YQpsaWJyYXJ5KGlncmFwaCkgICAgICMgRm9yIGdyYXBoaW5nCmxpYnJhcnkoZ2dyYXBoKSAgICAgIyBGb3IgZ3JhcGhpbmcKbGlicmFyeShzY2FsZXMpICAgICAjIEZvciBncmFwaGluZwpsaWJyYXJ5KGx1YnJpZGF0ZSkgICMgRm9yIHRpbWUgc2VyaWVzIHdvcmsKbGlicmFyeShncmlkRXh0cmEpICAjIEZvciBHcmlkIG1ha2luZwpsaWJyYXJ5KFZlbm5EaWFncmFtKSMgRm9yIFZlbm4gRGlhZ3JhbXMKYGBgCgojIyMgTG9hZGluZyB0aGUgZGF0YS1zZXQgc291cmNlZCBmcm9tIFJldHJhY3Rpb24gV2F0Y2ggb24gMTItSmFuLTIwMjQKCmBgYHtyfQpkYXRhPC0gcmVhZC5jc3YoInJldHJhY3Rpb25fd2F0Y2guY3N2IikKYWJkYzwtIHJlYWQuY3N2KCJhYmRjLmNzdiIpCnByZWRhdG9yeTwtIHJlYWQuY3N2KCJwcmVkYXRvcnkuY3N2IikKYGBgCgojIyMgRG9pbmcgc29tZSB3cmFuZ2xpbmcgb2YgdGhlIGRhdGEKYGBge3J9CiMgQ29udmVydCBkYXRlcyB0byBQT1NJWCBmb3JtYXQgZm9yIHRoZSBwdXBvc2Ugb2YgY29tcHV0YXRpb24KZGF0YSRPcmlnaW5hbFBhcGVyRGF0ZSA8LSBhcy5QT1NJWGN0KGRhdGEkT3JpZ2luYWxQYXBlckRhdGUsIGZvcm1hdCA9ICIlbS8lZC8lWSAlSDolTSIpCmRhdGEkUmV0cmFjdGlvbkRhdGUgPC0gYXMuUE9TSVhjdChkYXRhJFJldHJhY3Rpb25EYXRlLCBmb3JtYXQgPSAiJW0vJWQvJVkgJUg6JU0iKQoKIyBDb21wdXRlIHRoZSBkaWZmZXJlbmNlIGluIG1vbnRocwpkYXRhJER1cmF0aW9uSW5Nb250aHMgPC0gaW50ZXJ2YWwoc3RhcnQgPSBkYXRhJE9yaWdpbmFsUGFwZXJEYXRlLCBlbmQgPSBkYXRhJFJldHJhY3Rpb25EYXRlKSAvIG1vbnRocygxKQoKIyBFeHRyYWN0IHllYXIgZnJvbSBSZXRyYWN0aW9uRGF0ZQpkYXRhJFJldHJhY3Rpb25ZZWFyIDwtIHllYXIoZGF0YSRSZXRyYWN0aW9uRGF0ZSkKCiNDcmVhdGluZyBDbGVhbiBuYW1lcwpkYXRhPC0gZGF0YSAlPiUKICBjbGVhbl9uYW1lcygpCgphYmRjPC0gYWJkYyU+JQogIGNsZWFuX25hbWVzKCkKCnByZWRhdG9yeTwtIHByZWRhdG9yeSAlPiUKICBjbGVhbl9uYW1lcygpCmBgYAoKIyMjIENyZWF0aW5nIHRoZSBsaXN0cwpgYGB7cn0KYWJkY19saXN0IDwtIHVuaXF1ZSh0b2xvd2VyKGFiZGMkam91cm5hbCkpCnJldHJhY3Rpb25fbGlzdCA8LSB1bmlxdWUodG9sb3dlcihkYXRhJGpvdXJuYWwpKQpwcmVkYXRvcnlfbGlzdCA8LSB1bmlxdWUodG9sb3dlcihwcmVkYXRvcnkkam91cm5hbCkpCmBgYAoKIyMjIFRyeWluZyB0byBjcmVhdGUgYSB2ZW5uIGRpYWdyYW0gdG8gc2VlIGhvdyB0aGVzZSBzZXRzIGludGVyc2VjdApgYGB7cn0KIyBEZWZpbmUgYSBsaXN0IG9mIGxpc3RzIGZvciB0aGUgVmVubiBkaWFncmFtCmxpc3Rfb2ZfbGlzdHMgPC0gbGlzdCgKICBBQkRDID0gYWJkY19saXN0LAogIFJldHJhY3Rpb24gPSByZXRyYWN0aW9uX2xpc3QsCiAgUHJlZGF0b3J5ID0gcHJlZGF0b3J5X2xpc3QKKQoKIyBTcGVjaWZ5IHRoZSBmaWxlbmFtZSBmb3IgdGhlIG91dHB1dApvdXRwdXRfZmlsZW5hbWUgPC0gInZlbm5fZGlhZ3JhbS5wbmciCgojIENyZWF0ZSBhbmQgc2F2ZSB0aGUgVmVubiBkaWFncmFtCnZlbm4ucGxvdCA8LSB2ZW5uLmRpYWdyYW0oCiAgeCA9IGxpc3Rfb2ZfbGlzdHMsCiAgY2F0ZWdvcnkubmFtZXMgPSBjKCJBQkRDIiwgIlJldHJhY3Rpb24iLCAiUHJlZGF0b3J5IiksCiAgZmlsZW5hbWUgPSBvdXRwdXRfZmlsZW5hbWUKKQpgYGAKCgpObyBEaXJlY3QgcmVsYXRpb25zaGlwIGJldHdlZW4gcHJlZGF0b3J5IHByYWN0aWNlcyBhbmQgcmV0cmFjdGlvbnM6IFRoZSBmYWN0IHRoYXQgdGhlcmUgYXJlIG1hbnkgcmV0cmFjdGlvbnMgbm90IGxpbmtlZCB0byBwcmVkYXRvcnkgam91cm5hbHMgbWlnaHQgc3VnZ2VzdCB0aGF0IHByZWRhdG9yeSBwcmFjdGljZXMgYXJlIG5vdCB0aGUgb25seSByZWFzb24gZm9yIHJldHJhY3Rpb25zLiBSZXRyYWN0aW9ucyBjYW4gb2NjdXIgaW4gYW55IGpvdXJuYWwgYW5kIG1heSBiZSBkdWUgdG8gZmFjdG9ycyBsaWtlIGRhdGEgZmFicmljYXRpb24sIHBsYWdpYXJpc20sIG9yIG90aGVyIGV0aGljYWwgaXNzdWVzLgoKT3ZlcmxhcCBiZXR3ZWVuIHByZWRhdG9yeSBhbmQgcmV0cmFjdGlvbjogVGhlcmUgaXMgYW4gb3ZlcmxhcCBvZiBqdXN0IG9uZSBqb3VybmFsIGJldHdlZW4gdGhlIHByZWRhdG9yeSBsaXN0IGFuZCB0aGUgQUJEQyBsaXN0LCBzdWdnZXN0aW5nIHRoYXQgdGhlIEFCREMgbGlzdCBpcyBsYXJnZWx5IHN1Y2Nlc3NmdWwgaW4gYXZvaWRpbmcgcHJlZGF0b3J5IGpvdXJuYWxzLiBIb3dldmVyLCB0aGUgcHJlc2VuY2Ugb2YgdGhhdCBvbmUgam91cm5hbCBpbmRpY2F0ZXMgdGhhdCBubyB2ZXR0aW5nIHByb2Nlc3MgaXMgY29tcGxldGVseSBmb29scHJvb2YuCgpSZXRyYWN0aW9ucyBhcmUgbm90IGxpbWl0ZWQgdG8gUHJlZGF0b3J5IEpvdXJuYWxzOiBUaGUgbGFyZ2VyIG51bWJlciBvZiByZXRyYWN0aW9ucyAoNzgyMCkgbm90IGFzc29jaWF0ZWQgd2l0aCBwcmVkYXRvcnkgam91cm5hbHMgaW1wbGllcyB0aGF0IHJldHJhY3Rpb25zIGFyZSBhIGJyb2FkZXIgaXNzdWUgaW4gYWNhZGVtaWMgcHVibGlzaGluZywgcG90ZW50aWFsbHkgZHVlIHRvIGZhY3RvcnMgbGlrZSBob25lc3QgZXJyb3JzLCBtaXNjb25kdWN0LCBvciBwcm9ibGVtcyBpbiB0aGUgcGVlci1yZXZpZXcgcHJvY2VzcyBldmVuIGluIG5vbi1wcmVkYXRvcnkgam91cm5hbHMuCgpDb25zaWRlcmluZyBvbmx5IG9uZSBwcmVkYXRvcnkgam91cm5hbCBvZiB0aGUgMTE0NyB0aGF0IGFyZSBsaXN0ZWQsIGhhcyBldmVyIGhhZCBhIHJldHJhY3RlZCBhcnRpY2xlIGluIGl0LCBpcyB0aGVyZSBzb21ldGhpbmcgdGhhdCB3ZSBhcmUgb3ZlcnNlZWluZz8KCiMjIEZpbHRlciBkYXRhIGZvciByb3dzIHdoZXJlIGFydGljbGVfdHlwZSBpcyAiUmVzZWFyY2ggQXJ0aWNsZSIgb3IgIkFydGljbGUgaW4gUHJlc3MiCmBgYHtyfQojIFRoaXMgaXMgdG8gZW5zdXJlIHRoYXQgdGhlcmUgYXJlIG5vIGNvbmZlcmVuY2UgcGFwZXJzLCBib29rIGNoYXB0ZXJzLCBhbmQgb3RoZXJzIHRoYXQgYXJlIHRoZXJlIGluIHRoZSBkYXRhc2V0LiBPdXIgcmVzZWFyY2ggaXMgbGltaXRlZCB0byBqb3VybmFsIHB1YmxpY2F0aW9ucyBvbmx5LiAKZmlsdGVyZWRfZGF0YSA8LSBkYXRhW2dyZXBsKCJSZXNlYXJjaCBBcnRpY2xlIiwgZGF0YSRhcnRpY2xlX3R5cGUpIHwgZ3JlcGwoIkFydGljbGUgaW4gUHJlc3MiLCBkYXRhJGFydGljbGVfdHlwZSksIF0KYGBgCgojIyBMb29raW5nIG9ubHkgYXQgdGhlIGludGVyc2VjdGlvbiBvZiBBQkRDIGFuZCBSZXRyYWN0ZWQuIApgYGB7cn0KcmV0X2ludF9hYmRjIDwtIGZpbHRlcmVkX2RhdGEgJT4lCiAgZmlsdGVyKAogICAgdG9sb3dlcihmaWx0ZXJlZF9kYXRhJGpvdXJuYWwpICVpbiUgdG9sb3dlcihhYmRjJGpvdXJuYWwpICMgQ29udmVydGluZyB0byBsb3dlciBjYXNlIHRvIGVuc3VyZSB0aGF0IGNhc2UgbWlzbWF0Y2hlcyBkbyBub3QgY2FzZSBpc3N1ZXMgaW4gbWF0Y2hpbmcKICApCgp3cml0ZS5jc3YocmV0X2ludF9hYmRjLCAicmV0X2ludF9hYmRjLmNzdiIpICMgVGhpcyBpcyBzbyB0aGF0IFBhcmkgY2FuIHNlZSB0aGUgZGF0YSAKYGBgCgpUaGVyZSBhcmUgOTUxIGRhdGEgcG9pbnRzIHdpdGggdGhlIGNvbmZlcmVuY2UgYXJ0aWNsZXMsIGFuZCA4ODMgd2l0aG91dCB0aGUgY29uZmVyZW5jZSBhbmQgb3RoZXIgdHlwZXMgb2YgYXJ0aWNsZXMuICBJdCBpcyB0aGVzZSA4ODMgYXJ0aWNsZXMgdGhhdCB3ZSBmb2N1cyBvdXIgYXR0ZW50aW9uIG9uLiAKCiMjIExldCdzIGp1c3QgZGVzY3JpYmUgdGhpcyBkYXRhc2V0LiBUaGlzIGlzIGZvciB1cyB0byBtZW50aW9uIGluIHRoZSBpbnRyb2R1Y3Rpb24gc2VjdGlvbgpgYGB7cn0KIyBTZWxlY3QgdGhlIHNwZWNpZmllZCBjb2x1bW5zCm91cl9pbnRlcmVzdCA8LSBzZWxlY3QocmV0X2ludF9hYmRjLCByZWNvcmRfaWQsIHN1YmplY3QsIHRpdGxlLCBvcmlnaW5hbF9wYXBlcl9kYXRlLCByZWFzb24sIGF1dGhvcikKYGBgCgojIyBQbG90IEF2ZXJhZ2UgTnVtYmVyIG9mIFN1YmplY3RzIHBlciBQYXBlciBPdmVyIFRpbWUsIGFuZCB0aGUgbnVtYmVyIG9mIHJldHJhY3RlZCBhcnRjaWxlcyBpbiB0aGUgQUJEQwpgYGB7cn0KIyBDYWxjdWxhdGUgdGhlIG51bWJlciBvZiBzdWJqZWN0cyBwZXIgcmVjb3JkCm91cl9pbnRlcmVzdCRzdWJqZWN0X2NvdW50IDwtIHNhcHBseShzdHJzcGxpdChvdXJfaW50ZXJlc3Qkc3ViamVjdCwgIjsiKSwgZnVuY3Rpb24oeCkgc3VtKG56Y2hhcih4KSkpCgojIEV4dHJhY3QgdGhlIHllYXIgZnJvbSB0aGUgb3JpZ2luYWwgcGFwZXIgZGF0ZQpvdXJfaW50ZXJlc3QkeWVhciA8LSBmb3JtYXQob3VyX2ludGVyZXN0JG9yaWdpbmFsX3BhcGVyX2RhdGUsICIlWSIpCgojIEVuc3VyZSB5ZWFyIGlzIHRyZWF0ZWQgYXMgYSBjb250aW51b3VzIHZhcmlhYmxlCm91cl9pbnRlcmVzdCR5ZWFyIDwtIGFzLm51bWVyaWMob3VyX2ludGVyZXN0JHllYXIpCgojIENyZWF0ZSBhIHN1bW1hcnkgZGF0YSBmcmFtZQp5ZWFybHlfc3VtbWFyeSA8LSBvdXJfaW50ZXJlc3QgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgc3VtbWFyaXplKAogICAgcmVjb3JkX2NvdW50ID0gbigpLAogICAgYXZnX3N1YmplY3RfY291bnQgPSBtZWFuKHN1YmplY3RfY291bnQsIG5hLnJtID0gVFJVRSkKICApICU+JQogIHVuZ3JvdXAoKQoKIyBFbnN1cmUgd2UgaGF2ZSBhIHJvdyBmb3IgZXZlcnkgeWVhciBpbiB0aGUgcmFuZ2UgZnJvbSAyMDAwIHRvIDIwMjIKeWVhcmx5X3N1bW1hcnkgPC0gZGF0YS5mcmFtZSh5ZWFyID0gMTk5NToyMDIyKSAlPiUKICBsZWZ0X2pvaW4oeWVhcmx5X3N1bW1hcnksIGJ5ID0gInllYXIiKSAlPiUKICByZXBsYWNlX25hKGxpc3QocmVjb3JkX2NvdW50ID0gMCwgYXZnX3N1YmplY3RfY291bnQgPSAwKSkKCiMgRmluZCB0aGUgbWF4aW11bXMgZm9yIHNjYWxpbmcgdGhlIHNlY29uZGFyeSBheGlzCm1heF9yZWNvcmRzIDwtIG1heCh5ZWFybHlfc3VtbWFyeSRyZWNvcmRfY291bnQpCm1heF9hdmdfc3ViamVjdHMgPC0gbWF4KHllYXJseV9zdW1tYXJ5JGF2Z19zdWJqZWN0X2NvdW50KQoKIyBDcmVhdGUgdGhlIGxpbmUgcGxvdCB3aXRoIHR3byB5LWF4ZXMgYW5kIGNvbG9yZWQgYXhpcyBsYWJlbHMKZ2dwbG90KHllYXJseV9zdW1tYXJ5LCBhZXMoeCA9IHllYXIpKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gcmVjb3JkX2NvdW50KSwgY29sb3IgPSAiYmx1ZSIpICsKICBsYWJzKHggPSAiWWVhciIsIHkgPSAiTnVtYmVyIG9mIFJlY29yZHMiLCB0aXRsZSA9ICJOdW1iZXIgb2YgUmVjb3JkcyBhbmQgQXZlcmFnZSBOdW1iZXIgb2YgU3ViamVjdHMgcGVyIFBhcGVyIG92ZXIgdGltZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJibHVlIikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICAiTnVtYmVyIG9mIFJlY29yZHMiLAogICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+IC4gKiBtYXhfYXZnX3N1YmplY3RzIC8gbWF4X3JlY29yZHMsIG5hbWUgPSAiQXZlcmFnZSBOdW1iZXIgb2YgU3ViamVjdHMiLCBsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKQogICkgKwogIGdlb21fbGluZShhZXMoeSA9IGF2Z19zdWJqZWN0X2NvdW50ICogbWF4X3JlY29yZHMgLyBtYXhfYXZnX3N1YmplY3RzKSwgY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHRoZW1lKGF4aXMudGl0bGUueS5yaWdodCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJyZWQiKSkKYGBgClRoaXMgY2hhcnQgc2hvd3MgdXMgdGhhdCBmcm9tIHRoZSB0dXJuIG9mIHRoZSBjZW50dXJ5LCB0aGUgaWRlYSBvZiBpbnRlciBkaXNjaXBsaW5hcnkgcmVzZWFyY2ggKGRlZmluZWQgYXMgcmVzZWFyY2ggYmVpbmcgY2FycmllZCBvdXQgaW4gbXVsdGlwbGUgc3ViamVjdHMgd2l0aGluIHRoZSBzYW1lIG1ldGEgc3ViamVjdCkgaGFzIGluY3JlYXNlZCBmcm9tIGp1c3Qgb3ZlciAxIHRvIG5lYXJseSAzLiBUaGlzIGlzIGEgbWFzc2l2ZSBzaGlmdCAtIGFuZCBzb21ld2hhdCBjb25jZXJuaW5nLiAKCiMjIENoZWNraW5nIGlmIHRoZSBzYW1lIHRyZW5kIGFsc28gYXBwZWFycyBpbiB0aGUgbWV0YXN1YmplY3QgcmVhbG0KYGBge3J9CiMgRGVmaW5lIHRoZSBtYXBwaW5nIG9mIGNvZGVzIHRvIG1ldGFzdWJqZWN0cwptZXRhc3ViamVjdHNfbWFwIDwtIGMoCiAgIkIvVCIgPSAiQnVzaW5lc3MgYW5kIFRlY2hub2xvZ3kiLAogICJCTFMiID0gIkJhc2ljIExpZmUgU2NpZW5jZXMiLAogICJFTlYiID0gIkVudmlyb25tZW50YWwgU2NpZW5jZXMiLAogICJIU0MiID0gIkhlYWx0aCBTY2llbmNlcyIsCiAgIkhVTSIgPSAiSHVtYW5pdGllcyIsCiAgIlBIWSIgPSAiUGh5c2ljYWwgU2NpZW5jZXMiLAogICJTT0MiID0gIlNvY2lhbCBTY2llbmNlcyIKKQoKIyBFeHRyYWN0IGFuZCBtYXAgbWV0YXN1YmplY3RzCm91cl9pbnRlcmVzdCA8LSBvdXJfaW50ZXJlc3QgJT4lCiAgbXV0YXRlKAogICAgeWVhciA9IGFzLm51bWVyaWMoZm9ybWF0KG9yaWdpbmFsX3BhcGVyX2RhdGUsICIlWSIpKSwKICAgIG1ldGFzdWJqZWN0X2NvZGVzID0gc3RyX2V4dHJhY3RfYWxsKHN1YmplY3QsICJcXChcXHcrL1xcdytcXCl8XFwoXFx3K1xcKSIpLAogICAgbWV0YXN1YmplY3RzID0gbGFwcGx5KG1ldGFzdWJqZWN0X2NvZGVzLCBmdW5jdGlvbihjb2RlcykgewogICAgICB1bmlxdWVfY29kZXMgPC0gdW5pcXVlKGNvZGVzKQogICAgICBzYXBwbHkodW5pcXVlX2NvZGVzLCBmdW5jdGlvbihjb2RlKSBtZXRhc3ViamVjdHNfbWFwW3N1YnN0cihjb2RlLCAyLCBuY2hhcihjb2RlKSAtIDEpXSkKICAgIH0pLAogICAgbWV0YXN1YmplY3RfY291bnQgPSBzYXBwbHkobWV0YXN1YmplY3RzLCBsZW5ndGgpCiAgKQoKIyBDcmVhdGUgYSBzdW1tYXJ5IGRhdGEgZnJhbWUgZm9yIG1ldGFzdWJqZWN0cwp5ZWFybHlfbWV0YXN1YmplY3Rfc3VtbWFyeSA8LSBvdXJfaW50ZXJlc3QgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgc3VtbWFyaXplKAogICAgYXZnX21ldGFzdWJqZWN0X2NvdW50ID0gbWVhbihtZXRhc3ViamVjdF9jb3VudCwgbmEucm0gPSBUUlVFKSwKICAgIHJlY29yZF9jb3VudCA9IG4oKSAgIyBBc3N1bWluZyB5b3Ugd2FudCB0byBhbHNvIHBsb3QgdGhlIG51bWJlciBvZiByZWNvcmRzCiAgKSAlPiUKICB1bmdyb3VwKCkKCiMgRW5zdXJlIHdlIGhhdmUgYSByb3cgZm9yIGV2ZXJ5IHllYXIgaW4gdGhlIHJhbmdlCnllYXJseV9tZXRhc3ViamVjdF9zdW1tYXJ5IDwtIGRhdGEuZnJhbWUoeWVhciA9IDE5OTU6MjAyMikgJT4lCiAgbGVmdF9qb2luKHllYXJseV9tZXRhc3ViamVjdF9zdW1tYXJ5LCBieSA9ICJ5ZWFyIikgJT4lCiAgcmVwbGFjZV9uYShsaXN0KGF2Z19tZXRhc3ViamVjdF9jb3VudCA9IDAsIHJlY29yZF9jb3VudCA9IDApKQojIEZpbmQgdGhlIG1heGltdW0gdmFsdWUgdG8gc2V0IGFzIHRoZSB1cHBlciBsaW1pdCBmb3IgYm90aCB5LWF4ZXMKbWF4X2NvdW50IDwtIG1heCh5ZWFybHlfbWV0YXN1YmplY3Rfc3VtbWFyeSRyZWNvcmRfY291bnQsIG5hLnJtID0gVFJVRSkKbWF4X2F2Z19tZXRhc3ViamVjdHMgPC0gbWF4KHllYXJseV9tZXRhc3ViamVjdF9zdW1tYXJ5JGF2Z19tZXRhc3ViamVjdF9jb3VudCwgbmEucm0gPSBUUlVFKQpjb21tb25fbGltaXQgPC0gbWF4KG1heF9jb3VudCwgbWF4X2F2Z19tZXRhc3ViamVjdHMpCgojIEZpbmQgdGhlIG1heGltdW0gdmFsdWUgdG8gdXNlIGFzIHRoZSB1cHBlciBsaW1pdCBmb3IgdGhlIHNlY29uZGFyeSB5LWF4aXMKbWF4X3JlY29yZHMgPC0gbWF4KHllYXJseV9tZXRhc3ViamVjdF9zdW1tYXJ5JHJlY29yZF9jb3VudCwgbmEucm0gPSBUUlVFKQptYXhfYXZnX21ldGFzdWJqZWN0cyA8LSBtYXgoeWVhcmx5X21ldGFzdWJqZWN0X3N1bW1hcnkkYXZnX21ldGFzdWJqZWN0X2NvdW50LCBuYS5ybSA9IFRSVUUpCgojIENyZWF0ZSB0aGUgbGluZSBwbG90IHdpdGggYWRqdXN0ZWQgYXhpcyBzY2FsZXMKZ2dwbG90KHllYXJseV9tZXRhc3ViamVjdF9zdW1tYXJ5LCBhZXMoeCA9IHllYXIpKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gcmVjb3JkX2NvdW50KSwgY29sb3IgPSAiYmx1ZSIpICsgIyBQbG90IG51bWJlciBvZiByZWNvcmRzIGluIGJsdWUKICBsYWJzKHggPSAiWWVhciIsIHkgPSAiTnVtYmVyIG9mIFJlY29yZHMiLCB0aXRsZSA9ICJOdW1iZXIgb2YgUmVjb3JkcyBhbmQgQXZlcmFnZSBOdW1iZXIgb2YgRGlzY2lwbGluZXMgcGVyIFBhcGVyIG92ZXIgdGltZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImJsdWUiKSwKICAgIGF4aXMudGl0bGUueS5yaWdodCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJyZWQiKQogICkgKwogIHNjYWxlX3lfY29udGludW91cygKICAgIG5hbWUgPSAiTnVtYmVyIG9mIFJlY29yZHMiLAogICAgbGltaXRzID0gYygwLCBtYXhfcmVjb3JkcyksICMgU2V0IGxpbWl0cyBmb3IgdGhlIHByaW1hcnkgeS1heGlzCiAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4gLiAqIG1heF9hdmdfbWV0YXN1YmplY3RzIC8gbWF4X3JlY29yZHMsIG5hbWUgPSAiQXZlcmFnZSBOdW1iZXIgb2YgRGlzY2lwbGluZXMiLCBsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKQogICkgKwogIGdlb21fbGluZShhZXMoeSA9IGF2Z19tZXRhc3ViamVjdF9jb3VudCAqIG1heF9yZWNvcmRzIC8gbWF4X2F2Z19tZXRhc3ViamVjdHMpLCBjb2xvciA9ICJyZWQiLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArICMgUGxvdCBhdmcgbWV0YXN1YmplY3RzIGluIHJlZAogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDE5OTUsIDIwMjIpKSAjIFNldCB4LWF4aXMgbGltaXRzIGZyb20gMTk4MCB0byAyMDIyCmBgYApUaGUgdHJlbmQgaGVyZSBhbHNvIGFwcGVhcnMgc29tZXdoYXQgY29uc2lzdGVudCB3aXRoIHRoZSBzdWJqZWN0cy4gVGhpcyBtZWFucyB0aGF0IHJldHJhY3RlZCBwYXBlcnMgYXJlIHNsb3dseSBiZWNvbWluZyBpbnRlciBkaXNjaXBsaW5hcnkgaW4gbmF0dXJlLiAKCgoKCiMjIE5vdywgd3cgY3JlYXRlIGEgY29ycmVsYXRpb24gcGxvdCB0byBzZWUgd2hpY2ggRGlzY2lwbGluZXMga2VlcCBvY2N1cmluZyB0b2dldGhlci4gSSBhbSBub3QgZG9pbmcgdGhlIHJlZ3VsYXIgc3ViamVjdHMgYmVjYXN1ZSB0aGF0IHdvdWxkIGJlIHRvbyBjbHV0dGVyZWQgaW4gbXkgb3Bpbmlvbi4gCmBgYHtyfQojIEV4dHJhY3QgbWV0YS1zdWJqZWN0cyBmcm9tIHRoZSAnc3ViamVjdCcgY29sdW1uCm91cl9pbnRlcmVzdCRtZXRhX3N1YmplY3RzIDwtIHN0cl9leHRyYWN0X2FsbChvdXJfaW50ZXJlc3Qkc3ViamVjdCwgIlxcKC4qP1xcKSIpCgojIENyZWF0ZSBhIHVuaXF1ZSBsaXN0IG9mIGFsbCBtZXRhLXN1YmplY3RzCmFsbF9tZXRhX3N1YmplY3RzIDwtIHVuaXF1ZSh1bmxpc3Qob3VyX2ludGVyZXN0JG1ldGFfc3ViamVjdHMpKQoKIyBGdW5jdGlvbiB0byBjcmVhdGUgZHVtbXkgdmFyaWFibGVzCmNyZWF0ZV9kdW1teSA8LSBmdW5jdGlvbihtZXRhX3N1YmplY3RzLCBzdWJqZWN0KSB7CiAgYXMuaW50ZWdlcihzdWJqZWN0ICVpbiUgbWV0YV9zdWJqZWN0cykKfQoKIyBBcHBseSB0aGUgZnVuY3Rpb24gdG8gY3JlYXRlIGR1bW15IHZhcmlhYmxlcyBmb3IgZWFjaCBtZXRhLXN1YmplY3QKZm9yIChtZXRhX3N1YmplY3QgaW4gYWxsX21ldGFfc3ViamVjdHMpIHsKICBvdXJfaW50ZXJlc3RbW21ldGFfc3ViamVjdF1dIDwtIHNhcHBseShvdXJfaW50ZXJlc3QkbWV0YV9zdWJqZWN0cywgY3JlYXRlX2R1bW15LCBzdWJqZWN0ID0gbWV0YV9zdWJqZWN0KQp9CgojIFNlbGVjdCBvbmx5IHRoZSBtZXRhLXN1YmplY3QgZHVtbXkgdmFyaWFibGVzCm1ldGFfc3ViamVjdF9jb2xzIDwtIGFsbF9tZXRhX3N1YmplY3RzCgojIENhbGN1bGF0ZSB0aGUgY29ycmVsYXRpb24gbWF0cml4CmNvcl9tYXRyaXggPC0gY29yKG91cl9pbnRlcmVzdFssIG1ldGFfc3ViamVjdF9jb2xzXSwgdXNlID0gImNvbXBsZXRlLm9icyIpCgoKIyBNZWx0IHRoZSBjb3JyZWxhdGlvbiBtYXRyaXggZm9yIHZpc3VhbGl6YXRpb24KbWVsdGVkX2Nvcl9tYXRyaXggPC0gbWVsdChjb3JfbWF0cml4KQoKIyBQbG90IHRoZSBjb3JyZWxhdGlvbiBtYXRyaXgKZ2dwbG90KGRhdGEgPSBtZWx0ZWRfY29yX21hdHJpeCwgYWVzKHggPSBWYXIxLCB5ID0gVmFyMiwgZmlsbCA9IHZhbHVlKSkgKwogIGdlb21fdGlsZSgpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQodmFsdWUsIDIpKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMykgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiLCBtaWQgPSAid2hpdGUiLCAKICAgICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDAsIGxpbWl0ID0gYygtMSwgMSksIHNwYWNlID0gIkxhYiIsIAogICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiUGVhcnNvblxuQ29ycmVsYXRpb24iKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgZ2d0aXRsZSgiSW50ZXIgRGlzY2lwbGluZSBDb3JyZWxhdGlvbiBDb21wYXJpc29uIikKCmBgYAoKVGhpcyBpcyB0aGUga2V5IGZvciB0aGUgcmVmZXJlbmNlIG9mIG90aGVyczogCihCL1QpOiBCdXNpbmVzcyBhbmQgVGVjaG5vbG9neQooQkxTKTogQmFzaWMgTGlmZSBTY2llbmNlcwooRU5WKTogRW52aXJvbm1lbnRhbCBTY2llbmNlcwooSFNDKTogSGVhbHRoIFNjaWVuY2VzCihIVU0pOkh1bWFuaXRpZXMKKFBIWSk6IFBoeXNpY2FsIFNjaWVuY2VzCihTT0MpOiBTb2NpYWwgU2NpZW5jZXMKClRoaXMgaW52ZXN0aWdhdGlvbiByZXZlYWxzIHRoYXQgdGhlcmUgYXJlIG5vIHR3byBzdWJqZWN0cyB0aGF0IGFyZSBzdHJvbmdseSBjb3JyZWxhdGVkLiBIb3dldmVyLCB3ZSBjYW4gdHJ5IHNvbWV0aGluZyBpbnRlcmVzdGluZyBoZXJlLiAKCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShyZXNoYXBlMikKbGlicmFyeShncmlkRXh0cmEpICMgVGhpcyBsaWJyYXJ5IGlzIHVzZWQgdG8gYXJyYW5nZSBnZ3Bsb3RzIHNpZGUgYnkgc2lkZQoKIyBFeHRyYWN0IG1ldGEtc3ViamVjdHMgZnJvbSB0aGUgJ3N1YmplY3QnIGNvbHVtbgpvdXJfaW50ZXJlc3QkbWV0YV9zdWJqZWN0cyA8LSBzdHJfZXh0cmFjdF9hbGwob3VyX2ludGVyZXN0JHN1YmplY3QsICJcXCguKj9cXCkiKQoKIyBDcmVhdGUgYSB1bmlxdWUgbGlzdCBvZiBhbGwgbWV0YS1zdWJqZWN0cwphbGxfbWV0YV9zdWJqZWN0cyA8LSB1bmlxdWUodW5saXN0KG91cl9pbnRlcmVzdCRtZXRhX3N1YmplY3RzKSkKCiMgRnVuY3Rpb24gdG8gY3JlYXRlIGR1bW15IHZhcmlhYmxlcwpjcmVhdGVfZHVtbXkgPC0gZnVuY3Rpb24obWV0YV9zdWJqZWN0cywgc3ViamVjdCkgewogIGFzLmludGVnZXIoc3ViamVjdCAlaW4lIG1ldGFfc3ViamVjdHMpCn0KCiMgQXBwbHkgdGhlIGZ1bmN0aW9uIHRvIGNyZWF0ZSBkdW1teSB2YXJpYWJsZXMgZm9yIGVhY2ggbWV0YS1zdWJqZWN0CmZvciAobWV0YV9zdWJqZWN0IGluIGFsbF9tZXRhX3N1YmplY3RzKSB7CiAgb3VyX2ludGVyZXN0W1ttZXRhX3N1YmplY3RdXSA8LSBzYXBwbHkob3VyX2ludGVyZXN0JG1ldGFfc3ViamVjdHMsIGNyZWF0ZV9kdW1teSwgc3ViamVjdCA9IG1ldGFfc3ViamVjdCkKfQoKIyBGaWx0ZXIgZGF0YSBmb3IgdGhlIHR3byBwZXJpb2RzCmRhdGFfdW50aWxfMjAxMCA8LSBvdXJfaW50ZXJlc3QgJT4lIGZpbHRlcih5ZWFyIDw9IDIwMTApCmRhdGFfYWZ0ZXJfMjAxMCA8LSBvdXJfaW50ZXJlc3QgJT4lIGZpbHRlcih5ZWFyID4gMjAxMCkKCiMgU2VsZWN0IG9ubHkgdGhlIG1ldGEtc3ViamVjdCBkdW1teSB2YXJpYWJsZXMgZm9yIGNvcnJlbGF0aW9uIGNhbGN1bGF0aW9uCm1ldGFfc3ViamVjdF9jb2xzIDwtIGFsbF9tZXRhX3N1YmplY3RzCgojIENhbGN1bGF0ZSB0aGUgY29ycmVsYXRpb24gbWF0cml4IGZvciBib3RoIHBlcmlvZHMKY29yX21hdHJpeF91bnRpbF8yMDEwIDwtIGNvcihkYXRhX3VudGlsXzIwMTBbLCBtZXRhX3N1YmplY3RfY29sc10sIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQpjb3JfbWF0cml4X2FmdGVyXzIwMTAgPC0gY29yKGRhdGFfYWZ0ZXJfMjAxMFssIG1ldGFfc3ViamVjdF9jb2xzXSwgdXNlID0gImNvbXBsZXRlLm9icyIpCgojIE1lbHQgdGhlIGNvcnJlbGF0aW9uIG1hdHJpY2VzIGZvciB2aXN1YWxpemF0aW9uCm1lbHRlZF9jb3JfbWF0cml4X3VudGlsXzIwMTAgPC0gbWVsdChjb3JfbWF0cml4X3VudGlsXzIwMTApCm1lbHRlZF9jb3JfbWF0cml4X2FmdGVyXzIwMTAgPC0gbWVsdChjb3JfbWF0cml4X2FmdGVyXzIwMTApCgojIEZ1bmN0aW9uIHRvIGNyZWF0ZSBhIGdncGxvdCBvZiB0aGUgY29ycmVsYXRpb24gbWF0cml4CmNyZWF0ZV9jb3JfcGxvdCA8LSBmdW5jdGlvbihtZWx0ZWRfY29yX21hdHJpeCkgewogIGdncGxvdChkYXRhID0gbWVsdGVkX2Nvcl9tYXRyaXgsIGFlcyh4ID0gVmFyMSwgeSA9IFZhcjIsIGZpbGwgPSB2YWx1ZSkpICsKICAgIGdlb21fdGlsZSgpICsKICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZCh2YWx1ZSwgMikpLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAzKSArCiAgICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIiwgbWlkID0gIndoaXRlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDAsIGxpbWl0cyA9IGMoLTEsIDEpLCBzcGFjZSA9ICJMYWIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiUGVhcnNvblxuQ29ycmVsYXRpb24iKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCn0KCiMgQ3JlYXRlIHRoZSBwbG90cwpwbG90X3VudGlsXzIwMTAgPC0gY3JlYXRlX2Nvcl9wbG90KG1lbHRlZF9jb3JfbWF0cml4X3VudGlsXzIwMTApCnBsb3RfYWZ0ZXJfMjAxMCA8LSBjcmVhdGVfY29yX3Bsb3QobWVsdGVkX2Nvcl9tYXRyaXhfYWZ0ZXJfMjAxMCkKCmxpYnJhcnkoZ3JpZEV4dHJhKQoKIyBBZGQgaW5kaXZpZHVhbCB0aXRsZXMgdG8gZWFjaCBwbG90CnBsb3RfdW50aWxfMjAxMCA8LSBwbG90X3VudGlsXzIwMTAgKyBnZ3RpdGxlKCJDb3JyZWxhdGlvbiBVbnRpbCAyMDEwIikgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKcGxvdF9hZnRlcl8yMDEwIDwtIHBsb3RfYWZ0ZXJfMjAxMCArIGdndGl0bGUoIkNvcnJlbGF0aW9uIEFmdGVyIDIwMTAiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKIyBDb21iaW5lIHRoZSBwbG90cyBzaWRlIGJ5IHNpZGUgd2l0aCBhIGNvbW1vbiB0aXRsZQpncmlkLmFycmFuZ2UocGxvdF91bnRpbF8yMDEwLCBwbG90X2FmdGVyXzIwMTAsIG5jb2wgPSAyLAogICAgICAgICAgICAgdG9wID0gdGV4dEdyb2IoIkludGVyIERpc2NpcGxpbmUgQ29ycmVsYXRpb24gQ29tcGFyaXNvbiIsIGdwID0gZ3Bhcihmb250ZmFjZSA9ICJib2xkIiwgZm9udHNpemUgPSAxNCkpKQoKCmBgYApUaGlzIHNob3dzIHRoYXQgdGhlcmUgaGFzIG5vdCByZWFsbHkgYmVlbiBhbnkgc2lnbmlmaWNhbnQgdHJlbmQuIElmIGFueXRoaW5nLCB0aGUgY29ycmVsYXRpb24gaGFzIGRyb3BwZWQgb3ZlciB0aW1lLiAKClRoaXMgcG9pbnRzIHRvIHRoZSBmYWN0IHRoYXQgdGhlcmUgdGhpcyBpc3N1ZSBpcyBub3QgcGFydGljdWxhcmx5IGxpbWl0ZWQgdG8gc29tZSBhcmVhcyAtIGJ1dCBtdWNoIG1vcmUgcmFtcGFudC4gCgpJbiBmYWN0LCBpZiB3ZSBzdGFydCBsb29raW5nIGF0IHRoZSB0aXRsZXMgb2YgdGhlIHBhcGVycywgd2UgYmVnaW4gdG8gZ2V0IGEgbXVjaCBiZXR0ZXIgcGljdHVyZS4gCgojIyBDcmVhdGUgYSBXb3JkIE1hcCBmcm9tIHRoZSAnVGl0bGUnIFZhcmlhYmxlCmBgYHtyfQpsaWJyYXJ5KHdvcmRjbG91ZCkKbGlicmFyeSh0bSkKCiMgQ3JlYXRlIGEgdGV4dCBjb3JwdXMKY29ycHVzID0gQ29ycHVzKFZlY3RvclNvdXJjZShvdXJfaW50ZXJlc3QkdGl0bGUpKQoKIyBDbGVhbiB1cCB0aGUgdGV4dApjb3JwdXMgPSB0bV9tYXAoY29ycHVzLCBjb250ZW50X3RyYW5zZm9ybWVyKHRvbG93ZXIpKQpjb3JwdXMgPSB0bV9tYXAoY29ycHVzLCByZW1vdmVQdW5jdHVhdGlvbikKY29ycHVzID0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlTnVtYmVycykKY29ycHVzID0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygiZW5nbGlzaCIpKQoKIyBDcmVhdGUgYSB3b3JkIGNsb3VkCndvcmRjbG91ZChjb3JwdXMsIG1heC53b3JkcyA9IDEwMCkKYGBgCgoKV2VsbCwgd2UgaGF2ZSB0byBzcGVhayBhYm91dCB0aGlzIHRlYW0hCgoKTGV0IG1lIGp1c3QgZmluZCBvdXQgaWYgdGhlcmUgaXMgc29tZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSByZWFzb25zIHRoYXQgYXJlIGNpdGVkIGZvciByZXRyYWN0aW9uIApgYGB7cn0KIyBTdGVwIDE6IFNwbGl0IHRoZSAncmVhc29uJyBmaWVsZCBpbnRvIGluZGl2aWR1YWwgcmVhc29ucyBhbmQgcmVtb3ZlIHRoZSAnKycgcHJlZml4CnJlYXNvbnNfbGlzdCA8LSBzdHJzcGxpdChnc3ViKCJeXFwrIiwgIiIsIG91cl9pbnRlcmVzdCRyZWFzb24pLCAiOyIpCgojIFN0ZXAgMjogSWRlbnRpZnkgdW5pcXVlIHJlYXNvbnMKdW5pcXVlX3JlYXNvbnMgPC0gdW5pcXVlKHVubGlzdChyZWFzb25zX2xpc3QpKQoKIyBTdGVwIDM6IENyZWF0ZSBkdW1teSB2YXJpYWJsZXMgZm9yIGVhY2ggdW5pcXVlIHJlYXNvbgpmb3IocmVhc29uIGluIHVuaXF1ZV9yZWFzb25zKSB7CiAgb3VyX2ludGVyZXN0W1tyZWFzb25dXSA8LSBzYXBwbHkocmVhc29uc19saXN0LCBmdW5jdGlvbih4KSBhcy5pbnRlZ2VyKHJlYXNvbiAlaW4lIHgpKQp9CgojIFNlbGVjdCBvbmx5IGR1bW15IHZhcmlhYmxlcyAoYW5kIGFueSBvdGhlciBudW1lcmljIHZhcmlhYmxlcyB5b3Ugd2FudCB0byBpbmNsdWRlKQpudW1lcmljX2RhdGEgPC0gb3VyX2ludGVyZXN0Wywgc2FwcGx5KG91cl9pbnRlcmVzdCwgaXMubnVtZXJpYyldCgojIENvbXB1dGUgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeCBmb3IgbnVtZXJpYyBkYXRhCmNvcl9tYXRyaXggPC0gY29yKG51bWVyaWNfZGF0YSkKCiMgTWVsdCB0aGUgY29ycmVsYXRpb24gbWF0cml4IGZvciB2aXN1YWxpemF0aW9uCm1lbHRlZF9jb3JfbWF0cml4IDwtIHJlc2hhcGUyOjptZWx0KGNvcl9tYXRyaXgpCgojIERlZmluZSBhIHRocmVzaG9sZCBmb3IgZGlzcGxheWluZyB0ZXh0CnRocmVzaG9sZCA8LSAwLjUKCiMgUGxvdCB0aGUgY29ycmVsYXRpb24gbWF0cml4CmdncGxvdChkYXRhID0gbWVsdGVkX2Nvcl9tYXRyaXgsIGFlcyh4PVZhcjEsIHk9VmFyMiwgZmlsbD12YWx1ZSkpICsKICAgIGdlb21fdGlsZSgpICsKICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBpZmVsc2UoYWJzKHZhbHVlKSA+IHRocmVzaG9sZCwgcm91bmQodmFsdWUsIDIpLCAnJykpLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAyLjUpICsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiLCBtaWQgPSAid2hpdGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG1pZHBvaW50ID0gMCwgbGltaXQgPSBjKC0xLDEpLCBzcGFjZSA9ICJMYWIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU9IlBlYXJzb25cbkNvcnJlbGF0aW9uIikgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDQpLAogICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgY29vcmRfZml4ZWQoKSAjIEVuc3VyZSBzcXVhcmUgY2VsbHMgCmBgYApUaGlzIGxvb2tzIGEgbGl0dGxlIGRpZmZpY3VsdCB0byBjb21wcmVoZW5kLkkgYW0gZ29pbmcgdG8gbWFwIHRoZW0gdG8gc29tZXRoaW5nIG1vcmUgZWFzeSB0byB1bmRlcnN0YW5kIGFuZCBjaGVjayBhZ2Fpbi4gCgojIyBDcmVhdGluZyBicm9hZGVyIHRoZW1lcy4gCmBgYHtyfQojIERlZmluZSB0aGUgcGF0dGVybnMgZm9yIGVhY2ggY2F0ZWdvcnkKcGF0dGVybnMgPC0gbGlzdCgKICBJbnRlbGxlY3R1YWxfUHJvcGVydHlfVmlvbGF0aW9ucyA9IGMoIlBsYWdpYXJpc20iLCAiRHVwbGljYXRpb24iLCAiRXVwaGVtaXNtcyBmb3IgUGxhZ2lhcmlzbSIsICJGYWxzZS9Gb3JnZWQgQXV0aG9yc2hpcCIpLAogIFJlc2VhcmNoX0ludGVncml0eV9hbmRfUXVhbGl0eV9Jc3N1ZXMgPSBjKCJOb3QgUmVwcm9kdWNpYmxlIiwgIlVucmVsaWFibGUgUmVzdWx0cyIsICJFcnJvciBpbiBUZXh0IiwgIkVycm9yIGluIEFuYWx5c2VzIiwgIkVycm9yIGluIE1ldGhvZHMiLCAiRXJyb3IgaW4gRGF0YSIsICJFcnJvciBpbiBSZXN1bHRzIiwgIkZhYnJpY2F0aW9uIiwgIkZhbHNpZmljYXRpb24iLCAiRXRoaWNhbCBWaW9sYXRpb25zIiwgIklzc3VlcyBBYm91dCBEYXRhIiksCiAgUGVlcl9SZXZpZXdfYW5kX0VkaXRvcmlhbF9Db25jZXJucyA9IGMoIkZha2UgUGVlciBSZXZpZXciLCAiUm9ndWUgRWRpdG9yIiwgIkludmVzdGlnYXRpb24gYnkgSm91cm5hbC9QdWJsaXNoZXIiLCAiRXJyb3IgYnkgSm91cm5hbC9QdWJsaXNoZXIiLCAiT2JqZWN0aW9ucyBieSBBdXRob3IiKSwKICBQb2xpY3lfYW5kX0xlZ2FsX0NvbmNlcm5zID0gYygiQnJlYWNoIG9mIFBvbGljeSIsICJJc3N1ZXMgYWJvdXQgUmVmZXJlbmNpbmciLCAiTGVnYWwgUmVhc29ucyIsICJMYWNrIG9mIEFwcHJvdmFsIiksCiAgUHVibGljYXRpb25fYW5kX0NvbW11bmljYXRpb25fSXNzdWVzID0gYygiV2l0aGRyYXdhbCIsICJMaW1pdGVkIG9yIE5vIEluZm9ybWF0aW9uIiwgIk5vdGljZSAtIExhY2sgb2YiLCAiQXV0aG9yIFVucmVzcG9uc2l2ZSIsICJVcGRhdGUgb2YgUHJpb3IgTm90aWNlIiksCiAgSW52ZXN0aWdhdGlvbnNfYW5kX0FjdGlvbnMgPSBjKCJJbnZlc3RpZ2F0aW9uIGJ5IFRoaXJkIFBhcnR5IiwgIkRvaW5nIHRoZSBSaWdodCBUaGluZyIpLAogIE1pc2NlbGxhbmVvdXNfSXNzdWVzID0gYygiRGF0ZSBvZiBSZXRyYWN0aW9uIiwgIlJhbmRvbWx5IEdlbmVyYXRlZCBDb250ZW50IiwgIk9yaWdpbmFsIERhdGEgbm90IFByb3ZpZGVkIiwgIkNvbmNlcm5zIEFib3V0IEltYWdlIikKKQoKIyBGdW5jdGlvbiB0byBjcmVhdGUgZHVtbXkgdmFyaWFibGVzIGZvciBjYXRlZ29yaWVzIGJhc2VkIG9uIHRoZSBwcmVzZW5jZSBvZiBjZXJ0YWluIHBhdHRlcm5zCmNyZWF0ZV9kdW1teV92YXJzIDwtIGZ1bmN0aW9uKGRmLCBwYXR0ZXJucykgewogIGZvciAoY2F0ZWdvcnkgaW4gbmFtZXMocGF0dGVybnMpKSB7CiAgICBwYXR0ZXJuIDwtIHBhdHRlcm5zW1tjYXRlZ29yeV1dCiAgICBkZltbY2F0ZWdvcnldXSA8LSBhcy5pbnRlZ2VyKHNhcHBseShkZiRyZWFzb24sIGZ1bmN0aW9uKHgpIHsKICAgICAgYW55KHNhcHBseShwYXR0ZXJuLCBmdW5jdGlvbih5KSBzdHJfZGV0ZWN0KHgsIHJlZ2V4KHksIGlnbm9yZV9jYXNlID0gVFJVRSkpKSkKICAgIH0pKQogIH0KICByZXR1cm4oZGYpCn0KCiMgQXBwbHkgdGhlIGZ1bmN0aW9uIHRvIHRoZSBkYXRhIGZyYW1lCm91cl9pbnRlcmVzdCA8LSBjcmVhdGVfZHVtbXlfdmFycyhvdXJfaW50ZXJlc3QsIHBhdHRlcm5zKQoKIyBFbnN1cmUgdGhlc2UgY29sdW1ucyBleGlzdCBpbiB5b3VyIG91cl9pbnRlcmVzdCBkYXRhZnJhbWUKc2VsZWN0ZWRfY29sdW1ucyA8LSBjKCJJbnRlbGxlY3R1YWxfUHJvcGVydHlfVmlvbGF0aW9ucyIsICJSZXNlYXJjaF9JbnRlZ3JpdHlfYW5kX1F1YWxpdHlfSXNzdWVzIiwgCiAgICAgICAgICAgICAgICAgICAgICAiUGVlcl9SZXZpZXdfYW5kX0VkaXRvcmlhbF9Db25jZXJucyIsICJQb2xpY3lfYW5kX0xlZ2FsX0NvbmNlcm5zIiwgCiAgICAgICAgICAgICAgICAgICAgICAiUHVibGljYXRpb25fYW5kX0NvbW11bmljYXRpb25fSXNzdWVzIiwgIkludmVzdGlnYXRpb25zX2FuZF9BY3Rpb25zIiwgCiAgICAgICAgICAgICAgICAgICAgICAiTWlzY2VsbGFuZW91c19Jc3N1ZXMiKQoKIyBDaGVjayBpZiBhbGwgc2VsZWN0ZWQgY29sdW1ucyBhcmUgcHJlc2VudCBpbiBvdXJfaW50ZXJlc3QKaWYoYWxsKHNlbGVjdGVkX2NvbHVtbnMgJWluJSBuYW1lcyhvdXJfaW50ZXJlc3QpKSkgewogICAgIyBTZWxlY3Qgb25seSB0aGUgc3BlY2lmaWVkIGR1bW15IHZhcmlhYmxlIGNvbHVtbnMKICAgIGR1bW15X2RhdGEgPC0gb3VyX2ludGVyZXN0Wywgc2VsZWN0ZWRfY29sdW1uc10KCiAgICAjIENhbGN1bGF0ZSB0aGUgY29ycmVsYXRpb24gbWF0cml4CiAgICBjb3JfbWF0cml4IDwtIGNvcihkdW1teV9kYXRhLCB1c2UgPSAiY29tcGxldGUub2JzIikgIyB1c2UgY29tcGxldGUub2JzIHRvIGhhbmRsZSBOQSB2YWx1ZXMKCiAgICAjIE1lbHQgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeCBmb3IgdmlzdWFsaXphdGlvbgogICAgbWVsdGVkX2Nvcl9tYXRyaXggPC0gcmVzaGFwZTI6Om1lbHQoY29yX21hdHJpeCkKCiAgICAjIFBsb3QgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeCB3aXRoIG51bWJlcnMKICAgIGdncGxvdChkYXRhID0gbWVsdGVkX2Nvcl9tYXRyaXgsIGFlcyh4PVZhcjEsIHk9VmFyMiwgZmlsbD12YWx1ZSkpICsKICAgICAgICBnZW9tX3RpbGUoKSArCiAgICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHZhbHVlLCAyKSksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDMpICsKICAgICAgICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIiwgbWlkID0gIndoaXRlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWlkcG9pbnQgPSAwLCBsaW1pdCA9IGMoLTEsMSksIHNwYWNlID0gIkxhYiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU9IlBlYXJzb25cbkNvcnJlbGF0aW9uIikgKwogICAgICAgIHRoZW1lX21pbmltYWwoKSArCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKfSBlbHNlIHsKICAgIHN0b3AoIk5vdCBhbGwgc3BlY2lmaWVkIGNvbHVtbnMgZXhpc3QgaW4gdGhlIGRhdGFmcmFtZS4iKQp9CgpgYGAKCkhlcmUgYXJlIG15IGtleSBvYnNlcnZhdGlvbnMgaW4gdGhpczogCgoxLiBJdCBsb29rcyBsaWtlIEludmVzdGlnYXRpb25zIGFuZCBNaXNjIGlzc3VlcyBrZWVwIGNvLW9jY3VyaW5nCjIuIFBvbGljeSBhbmQgbGVnYWwgY29uY2VybnMgc2VlbSB0byBkbyBzbyB0b28uIAozLiBJbnZlc3RpZ2F0aW9ucyBzZWVtIHRvIGZvbGxvdyB0aGUgUGVlciByZXZpZXcgY29uY2VybnMuIAo0LiBJbnZlc3RpZ2F0aW9ucyBhbHNvIHNlZW0gdG8gZm9sbG93IFJlc2VhcmNoIGludGVncml0eSBpc3N1ZXMuIAoKTm93IHRoaXMgYmVncyB0aGUgcXVlc3Rpb24sIGlzIHRoZXJlIHNvbWV0aGluZyBkaWZmZXJlbnQgdGhhdCdzIGdvaW5nIG9uIGluIHRoZSBnZW5lcmFsIHNldCBvZiBwYXBlcnM/IAoKTGV0IG1lIGp1c3QgY2hlY2sgdGhhdCBvdXQgaGVyZQoKI3RyeWluZyB0byBmaW5kIG91dCBpZiB0aGVyZSBhcmUgY29ycmVsYXRpb25zIGluIHRoZSBicm9hZGVyIGRhdGFzZXQgb2YgYWxsIHJldHJhY3Rpb25zLiAKCmBgYHtyfQojIERlZmluZSB0aGUgcGF0dGVybnMgZm9yIGVhY2ggY2F0ZWdvcnkKcGF0dGVybnMgPC0gbGlzdCgKICBJbnRlbGxlY3R1YWxfUHJvcGVydHlfVmlvbGF0aW9ucyA9IGMoIlBsYWdpYXJpc20iLCAiRHVwbGljYXRpb24iLCAiRXVwaGVtaXNtcyBmb3IgUGxhZ2lhcmlzbSIsICJGYWxzZS9Gb3JnZWQgQXV0aG9yc2hpcCIpLAogIFJlc2VhcmNoX0ludGVncml0eV9hbmRfUXVhbGl0eV9Jc3N1ZXMgPSBjKCJOb3QgUmVwcm9kdWNpYmxlIiwgIlVucmVsaWFibGUgUmVzdWx0cyIsICJFcnJvciBpbiBUZXh0IiwgIkVycm9yIGluIEFuYWx5c2VzIiwgIkVycm9yIGluIE1ldGhvZHMiLCAiRXJyb3IgaW4gRGF0YSIsICJFcnJvciBpbiBSZXN1bHRzIiwgIkZhYnJpY2F0aW9uIiwgIkZhbHNpZmljYXRpb24iLCAiRXRoaWNhbCBWaW9sYXRpb25zIiwgIklzc3VlcyBBYm91dCBEYXRhIiksCiAgUGVlcl9SZXZpZXdfYW5kX0VkaXRvcmlhbF9Db25jZXJucyA9IGMoIkZha2UgUGVlciBSZXZpZXciLCAiUm9ndWUgRWRpdG9yIiwgIkludmVzdGlnYXRpb24gYnkgSm91cm5hbC9QdWJsaXNoZXIiLCAiRXJyb3IgYnkgSm91cm5hbC9QdWJsaXNoZXIiLCAiT2JqZWN0aW9ucyBieSBBdXRob3IiKSwKICBQb2xpY3lfYW5kX0xlZ2FsX0NvbmNlcm5zID0gYygiQnJlYWNoIG9mIFBvbGljeSIsICJJc3N1ZXMgYWJvdXQgUmVmZXJlbmNpbmciLCAiTGVnYWwgUmVhc29ucyIsICJMYWNrIG9mIEFwcHJvdmFsIiksCiAgUHVibGljYXRpb25fYW5kX0NvbW11bmljYXRpb25fSXNzdWVzID0gYygiV2l0aGRyYXdhbCIsICJMaW1pdGVkIG9yIE5vIEluZm9ybWF0aW9uIiwgIk5vdGljZSAtIExhY2sgb2YiLCAiQXV0aG9yIFVucmVzcG9uc2l2ZSIsICJVcGRhdGUgb2YgUHJpb3IgTm90aWNlIiksCiAgSW52ZXN0aWdhdGlvbnNfYW5kX0FjdGlvbnMgPSBjKCJJbnZlc3RpZ2F0aW9uIGJ5IFRoaXJkIFBhcnR5IiwgIkRvaW5nIHRoZSBSaWdodCBUaGluZyIpLAogIE1pc2NlbGxhbmVvdXNfSXNzdWVzID0gYygiRGF0ZSBvZiBSZXRyYWN0aW9uIiwgIlJhbmRvbWx5IEdlbmVyYXRlZCBDb250ZW50IiwgIk9yaWdpbmFsIERhdGEgbm90IFByb3ZpZGVkIiwgIkNvbmNlcm5zIEFib3V0IEltYWdlIikKKQoKIyBGdW5jdGlvbiB0byBjcmVhdGUgZHVtbXkgdmFyaWFibGVzIGZvciBjYXRlZ29yaWVzIGJhc2VkIG9uIHRoZSBwcmVzZW5jZSBvZiBjZXJ0YWluIHBhdHRlcm5zCmNyZWF0ZV9kdW1teV92YXJzIDwtIGZ1bmN0aW9uKGRmLCBwYXR0ZXJucykgewogIGZvciAoY2F0ZWdvcnkgaW4gbmFtZXMocGF0dGVybnMpKSB7CiAgICBwYXR0ZXJuIDwtIHBhdHRlcm5zW1tjYXRlZ29yeV1dCiAgICBkZltbY2F0ZWdvcnldXSA8LSBhcy5pbnRlZ2VyKHNhcHBseShkZiRyZWFzb24sIGZ1bmN0aW9uKHgpIHsKICAgICAgYW55KHNhcHBseShwYXR0ZXJuLCBmdW5jdGlvbih5KSBzdHJfZGV0ZWN0KHgsIHJlZ2V4KHksIGlnbm9yZV9jYXNlID0gVFJVRSkpKSkKICAgIH0pKQogIH0KICByZXR1cm4oZGYpCn0KCm91cl9pbnRlcmVzdF90ZW1wPC0gb3VyX2ludGVyZXN0CgojIEFwcGx5IHRoZSBmdW5jdGlvbiB0byB0aGUgZGF0YSBmcmFtZQpvdXJfaW50ZXJlc3QgPC0gY3JlYXRlX2R1bW15X3ZhcnMoZGF0YSwgcGF0dGVybnMpCgojIEVuc3VyZSB0aGVzZSBjb2x1bW5zIGV4aXN0IGluIHlvdXIgb3VyX2ludGVyZXN0IGRhdGFmcmFtZQpzZWxlY3RlZF9jb2x1bW5zIDwtIGMoIkludGVsbGVjdHVhbF9Qcm9wZXJ0eV9WaW9sYXRpb25zIiwgIlJlc2VhcmNoX0ludGVncml0eV9hbmRfUXVhbGl0eV9Jc3N1ZXMiLCAKICAgICAgICAgICAgICAgICAgICAgICJQZWVyX1Jldmlld19hbmRfRWRpdG9yaWFsX0NvbmNlcm5zIiwgIlBvbGljeV9hbmRfTGVnYWxfQ29uY2VybnMiLCAKICAgICAgICAgICAgICAgICAgICAgICJQdWJsaWNhdGlvbl9hbmRfQ29tbXVuaWNhdGlvbl9Jc3N1ZXMiLCAiSW52ZXN0aWdhdGlvbnNfYW5kX0FjdGlvbnMiLCAKICAgICAgICAgICAgICAgICAgICAgICJNaXNjZWxsYW5lb3VzX0lzc3VlcyIpCgojIENoZWNrIGlmIGFsbCBzZWxlY3RlZCBjb2x1bW5zIGFyZSBwcmVzZW50IGluIG91cl9pbnRlcmVzdAppZihhbGwoc2VsZWN0ZWRfY29sdW1ucyAlaW4lIG5hbWVzKG91cl9pbnRlcmVzdCkpKSB7CiAgICAjIFNlbGVjdCBvbmx5IHRoZSBzcGVjaWZpZWQgZHVtbXkgdmFyaWFibGUgY29sdW1ucwogICAgZHVtbXlfZGF0YSA8LSBvdXJfaW50ZXJlc3RbLCBzZWxlY3RlZF9jb2x1bW5zXQoKICAgICMgQ2FsY3VsYXRlIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXgKICAgIGNvcl9tYXRyaXggPC0gY29yKGR1bW15X2RhdGEsIHVzZSA9ICJjb21wbGV0ZS5vYnMiKSAjIHVzZSBjb21wbGV0ZS5vYnMgdG8gaGFuZGxlIE5BIHZhbHVlcwoKICAgICMgTWVsdCB0aGUgY29ycmVsYXRpb24gbWF0cml4IGZvciB2aXN1YWxpemF0aW9uCiAgICBtZWx0ZWRfY29yX21hdHJpeCA8LSByZXNoYXBlMjo6bWVsdChjb3JfbWF0cml4KQoKICAgICMgUGxvdCB0aGUgY29ycmVsYXRpb24gbWF0cml4IHdpdGggbnVtYmVycwogICAgZ2dwbG90KGRhdGEgPSBtZWx0ZWRfY29yX21hdHJpeCwgYWVzKHg9VmFyMSwgeT1WYXIyLCBmaWxsPXZhbHVlKSkgKwogICAgICAgIGdlb21fdGlsZSgpICsKICAgICAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQodmFsdWUsIDIpKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMykgKwogICAgICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiLCBtaWQgPSAid2hpdGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDAsIGxpbWl0ID0gYygtMSwxKSwgc3BhY2UgPSAiTGFiIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZT0iUGVhcnNvblxuQ29ycmVsYXRpb24iKSArCiAgICAgICAgdGhlbWVfbWluaW1hbCgpICsKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCgp9IGVsc2UgewogICAgc3RvcCgiTm90IGFsbCBzcGVjaWZpZWQgY29sdW1ucyBleGlzdCBpbiB0aGUgZGF0YWZyYW1lLiIpCn0KCm91cl9pbnRlcmVzdDwtIG91cl9pbnRlcmVzdF90ZW1wCgoKYGBgCgpUaGlzIHByZXNlbnRzIHRoZSBhbiBpbnRlcmVzdGluZyBxdWVzdGlvbi4gQXJlIHRoZXJlIHR3byBkaWZmZXJlbnQgc3RvcmllcyBoZXJlPwoKQ09udHJhc3RpbmcgbWFuYWdlbWVudCB3aXRoIG90aGVyLCBub24gbWFuYWdtZW5ldCBmaWVsZHMuIApDcmVhdGluZyB0d28gc2VwYXJhdGUgc3Vic2V0cyBub3cgLSBvbmUgZm9yIGJ1c2luZXNzIHJlbGF0ZWQsIGFuZCBvbmUgZm9yIG5vbiBidXNpbmVzcwpgYGB7cn0KIyBEZWZpbmUgYnVzaW5lc3MtcmVsYXRlZCBzdWJqZWN0cwpidXNpbmVzc19zdWJqZWN0cyA8LSBjKCJCdXNpbmVzcyAtIE1hbmFnZW1lbnQiLCAKICAgICAgICAgICAgICAgICAgICAgICAiQnVzaW5lc3MgLSBFY29ub21pY3MiLCAKICAgICAgICAgICAgICAgICAgICAgICAiQnVzaW5lc3MgLSBNYXJrZXRpbmciLCAKICAgICAgICAgICAgICAgICAgICAgICAiQnVzaW5lc3MgLSBHZW5lcmFsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgIkJ1c2luZXNzIC0gTWFudWZhY3R1cmluZyIsIAogICAgICAgICAgICAgICAgICAgICAgICJCdXNpbmVzcyAtIEFjY291bnRpbmciKQoKIyBDcmVhdGUgYSBzaW5nbGUgcGF0dGVybiBzdHJpbmcgZm9yIG1hdGNoaW5nCnBhdHRlcm4gPC0gcGFzdGUoYnVzaW5lc3Nfc3ViamVjdHMsIGNvbGxhcHNlID0gInwiKQoKIyBUaGlzIGlzIHRoZSBCdXNpbmVzcyByZWxhdGVkIHN1YmplY3RzCmRhdGFfYnVzaW5lc3MgPC0gZGF0YSAlPiUKICBmaWx0ZXIoc3RyX2RldGVjdChzdWJqZWN0LCBwYXR0ZXJuKSkKCiMgVGhpcyBpcyB0aGUgTm9uIEJ1c2luZXNzIHJlbGF0ZWQgc3ViamVjdHMKZGF0YV9ub25idXNpbmVzcyA8LSBkYXRhICU+JQogIGZpbHRlcighc3RyX2RldGVjdChzdWJqZWN0LCBwYXR0ZXJuKSkKCmRhdGFfdGVtcDwtIGRhdGEKYGBgCgoKClRyeWluZyB0byBwbG90IGhvdyByZXRyYWN0aW9ucyBoYXZlIGJlZW4gaW4gTm9uIE1hbmFnZW1lbnQgZGlzY2lwbGluZXMKYGBge3J9CiMgUHJlcGFyZSBkYXRhCnllYXJseV9kYXRhIDwtIGRhdGFfbm9uYnVzaW5lc3MgJT4lCiAgZ3JvdXBfYnkocmV0cmFjdGlvbl95ZWFyKSAlPiUKICBzdW1tYXJpemUoYXZlcmFnZV9kdXJhdGlvbiA9IG1lYW4oZHVyYXRpb25faW5fbW9udGhzLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICByZXRyYWN0aW9uX2NvdW50ID0gbigpKQoKIyBOb3JtYWxpemUgdGhlIFJldHJhY3Rpb25Db3VudCBmb3IgYmV0dGVyIHZpc3VhbGl6YXRpb24KbWF4X2R1cmF0aW9uIDwtIG1heCh5ZWFybHlfZGF0YSRhdmVyYWdlX2R1cmF0aW9uLCBuYS5ybSA9IFRSVUUpCm1heF9jb3VudCA8LSBtYXgoeWVhcmx5X2RhdGEkcmV0cmFjdGlvbl9jb3VudCwgbmEucm0gPSBUUlVFKQp5ZWFybHlfZGF0YSROb3JtYWxpemVkQ291bnQgPC0geWVhcmx5X2RhdGEkcmV0cmFjdGlvbl9jb3VudCAvIG1heF9jb3VudCAqIG1heF9kdXJhdGlvbgoKcmV0cmFjdGlvbnNfbm9ubWFuYWdlbWVudDwtIGdncGxvdCh5ZWFybHlfZGF0YSwgYWVzKHggPSByZXRyYWN0aW9uX3llYXIpKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gYXZlcmFnZV9kdXJhdGlvbiwgZ3JvdXAgPSAxKSwgY29sb3IgPSAiYmx1ZSIpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gYXZlcmFnZV9kdXJhdGlvbiksIGNvbG9yID0gImJsdWUiKSArCiAgZ2VvbV9iYXIoYWVzKHkgPSBOb3JtYWxpemVkQ291bnQpLCBzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJyZWQiLCBhbHBoYSA9IDAuNSkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMTk5MCwgTkEpKSArICAjIExpbWl0aW5nIHgtYXhpcyB0byBzdGFydCBmcm9tIDE5NzArCgogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIkF2ZXJhZ2UgRHVyYXRpb24gaW4gTW9udGhzIiwgCiAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXMofiAuICogbWF4X2NvdW50IC8gbWF4X2R1cmF0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIk51bWJlciBvZiBSZXRyYWN0aW9ucyIpKSArCiAgbGFicyh0aXRsZSA9ICJSZXRyYWN0aW9ucyBvdmVyIHRoZSBZZWFyczogRHVyYXRpb24gYW5kIENvdW50IChOb24gTWFuYWdlbWVudCBEaXNjaXBsaW5lcykiLAogICAgICAgeCA9ICJSZXRyYWN0aW9uIFllYXIiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKVHJ5aW5nIHRvIHBsb3QgaG93IHJldHJhY3Rpb25zIGhhdmUgYmVlbiBpbiBNYW5hZ2VtZW50IGRpc2NpcGxpbmVzCmBgYHtyfQojIFByZXBhcmUgZGF0YQp5ZWFybHlfZGF0YSA8LSBkYXRhX2J1c2luZXNzICU+JQogIGdyb3VwX2J5KHJldHJhY3Rpb25feWVhcikgJT4lCiAgc3VtbWFyaXplKGF2ZXJhZ2VfZHVyYXRpb24gPSBtZWFuKGR1cmF0aW9uX2luX21vbnRocywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgcmV0cmFjdGlvbl9jb3VudCA9IG4oKSkKCiMgTm9ybWFsaXplIHRoZSBSZXRyYWN0aW9uQ291bnQgZm9yIGJldHRlciB2aXN1YWxpemF0aW9uCm1heF9kdXJhdGlvbiA8LSBtYXgoeWVhcmx5X2RhdGEkYXZlcmFnZV9kdXJhdGlvbiwgbmEucm0gPSBUUlVFKQptYXhfY291bnQgPC0gbWF4KHllYXJseV9kYXRhJHJldHJhY3Rpb25fY291bnQsIG5hLnJtID0gVFJVRSkKeWVhcmx5X2RhdGEkTm9ybWFsaXplZENvdW50IDwtIHllYXJseV9kYXRhJHJldHJhY3Rpb25fY291bnQgLyBtYXhfY291bnQgKiBtYXhfZHVyYXRpb24KCnJldHJhY3Rpb25zX21hbmFnZW1lbnQ8LSBnZ3Bsb3QoeWVhcmx5X2RhdGEsIGFlcyh4ID0gcmV0cmFjdGlvbl95ZWFyKSkgKwogIGdlb21fbGluZShhZXMoeSA9IGF2ZXJhZ2VfZHVyYXRpb24sIGdyb3VwID0gMSksIGNvbG9yID0gImJsdWUiKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IGF2ZXJhZ2VfZHVyYXRpb24pLCBjb2xvciA9ICJibHVlIikgKwogIGdlb21fYmFyKGFlcyh5ID0gTm9ybWFsaXplZENvdW50KSwgc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAicmVkIiwgYWxwaGEgPSAwLjUpICsKICAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDE5OTAsIE5BKSkgKyAgIyBMaW1pdGluZyB4LWF4aXMgdG8gc3RhcnQgZnJvbSAxOTcwKwoKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJBdmVyYWdlIER1cmF0aW9uIGluIE1vbnRocyIsIAogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4gLiAqIG1heF9jb3VudCAvIG1heF9kdXJhdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJOdW1iZXIgb2YgUmV0cmFjdGlvbnMiKSkgKwogIGxhYnModGl0bGUgPSAiUmV0cmFjdGlvbnMgb3ZlciB0aGUgWWVhcnM6IER1cmF0aW9uIGFuZCBDb3VudCAoTWFuYWdlbWVudCBEaXNjaXBsaW5lcykiLAogICAgICAgeCA9ICJSZXRyYWN0aW9uIFllYXIiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKRGlzcGxheWluZyB0aGUgcGxvdApgYGB7cn0KZ3JpZC5hcnJhbmdlKHJldHJhY3Rpb25zX21hbmFnZW1lbnQsIHJldHJhY3Rpb25zX25vbm1hbmFnZW1lbnQsIG5jb2wgPSAxKQpgYGAKClRyeWluZyB0byB1bmRlcnN0YW5kIHRoZSBkaXN0cmlidXRpb24gb2Ygc3ViamVjdHMgbm93LiAKCkRpc3RyaWJ1dGlvbiBvZiBTdWJqZWN0cyAtIE5vbiBNYW5hZ2VtZW50IFN1YmplY3RzCmBgYHtyfQojIFNlcGFyYXRlIHRoZSBzdWJqZWN0cyBpbnRvIGluZGl2aWR1YWwgcm93cwpkYXRhX3N1YmplY3RzIDwtIGRhdGFfbm9uYnVzaW5lc3MgJT4lCiAgICAgICAgICAgICAgICAgc2VwYXJhdGVfcm93cyhzdWJqZWN0LCBzZXAgPSAiO1xccyoiKQoKIyBDb3VudCB0aGUgb2NjdXJyZW5jZXMgb2YgZWFjaCBzdWJqZWN0CnN1YmplY3RfY291bnQgPC0gZGF0YV9zdWJqZWN0cyAlPiUKICAgICAgICAgICAgICAgICBjb3VudChzdWJqZWN0LCBzb3J0ID0gVFJVRSkKCiMgQ3JlYXRlIGEgaG9yaXpvbnRhbCBiYXIgY2hhcnQKZ2dwbG90KHN1YmplY3RfY291bnQsIGFlcyh5ID0gcmVvcmRlcihzdWJqZWN0LCBuKSwgeCA9IG4pKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNCkpICsKICAgIGxhYnMoeSA9ICJTdWJqZWN0IiwgeCA9ICJDb3VudCIsIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBTdWJqZWN0cyAtIE5vbiBNYW5hZ2VtZW50IikKYGBgCgpgYGB7cn0KIyBSZW5hbWUgdGhlIHN1YmplY3QgdG8gdGhlIGJyb2FkZXIgdGhlbWUgdGhhdCdzIHdyaXR0ZW4gaW4gdGhlIGJyYWNrZXRzCnN1YmplY3RfY291bnQgPC0gc3ViamVjdF9jb3VudCAlPiUKICBtdXRhdGUoc3ViamVjdCA9IHN0cl9tYXRjaChzdWJqZWN0LCAiXFwoKFteKV0rKVxcKSIpWywyXSkKCiMgUmVtb3ZlIE5BIHZhbHVlcyB0aGF0IG1pZ2h0IGhhdmUgYmVlbiBpbnRyb2R1Y2VkIGlmIHRoZXJlIHdlcmUgc3ViamVjdHMgd2l0aG91dCBicmFja2V0cwpzdWJqZWN0X2NvdW50IDwtIHN1YmplY3RfY291bnQgJT4lIAogIGZpbHRlcighaXMubmEoc3ViamVjdCkpCgojIENyZWF0ZSBhIGhvcml6b250YWwgYmFyIGNoYXJ0CmdncGxvdChzdWJqZWN0X2NvdW50LCBhZXMoeSA9IHJlb3JkZXIoc3ViamVjdCwgbiksIHggPSBuKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNikpICsKICBsYWJzKHkgPSAiU3ViamVjdCIsIHggPSAiQ291bnQiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgU3ViamVjdHMgLSBOb24gTWFuYWdlbWVudCBTdWJqZWN0cyIpCmBgYAoKRGlzdHJpYnV0aW9uIG9mIFN1YmplY3RzIC0gIE1hbmFnZW1lbnQgU3ViamVjdHMKYGBge3J9CiMgU2VwYXJhdGUgdGhlIHN1YmplY3RzIGludG8gaW5kaXZpZHVhbCByb3dzCmRhdGFfc3ViamVjdHMgPC0gZGF0YV9idXNpbmVzcyAlPiUKICAgICAgICAgICAgICAgICBzZXBhcmF0ZV9yb3dzKHN1YmplY3QsIHNlcCA9ICI7XFxzKiIpCgojIENvdW50IHRoZSBvY2N1cnJlbmNlcyBvZiBlYWNoIHN1YmplY3QKc3ViamVjdF9jb3VudCA8LSBkYXRhX3N1YmplY3RzICU+JQogICAgICAgICAgICAgICAgIGNvdW50KHN1YmplY3QsIHNvcnQgPSBUUlVFKQoKIyBDcmVhdGUgYSBob3Jpem9udGFsIGJhciBjaGFydApnZ3Bsb3Qoc3ViamVjdF9jb3VudCwgYWVzKHkgPSByZW9yZGVyKHN1YmplY3QsIG4pLCB4ID0gbikpICsKICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA0KSkgKwogICAgbGFicyh5ID0gIlN1YmplY3QiLCB4ID0gIkNvdW50IiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFN1YmplY3RzIC0gTWFuYWdlbWVudCIpCmBgYAoKYGBge3J9CiMgUmVuYW1lIHRoZSBzdWJqZWN0IHRvIHRoZSBicm9hZGVyIHRoZW1lIHRoYXQncyB3cml0dGVuIGluIHRoZSBicmFja2V0cwpzdWJqZWN0X2NvdW50IDwtIHN1YmplY3RfY291bnQgJT4lCiAgbXV0YXRlKHN1YmplY3QgPSBzdHJfbWF0Y2goc3ViamVjdCwgIlxcKChbXildKylcXCkiKVssMl0pCgojIFJlbW92ZSBOQSB2YWx1ZXMgdGhhdCBtaWdodCBoYXZlIGJlZW4gaW50cm9kdWNlZCBpZiB0aGVyZSB3ZXJlIHN1YmplY3RzIHdpdGhvdXQgYnJhY2tldHMKc3ViamVjdF9jb3VudCA8LSBzdWJqZWN0X2NvdW50ICU+JSAKICBmaWx0ZXIoIWlzLm5hKHN1YmplY3QpKQoKIyBDcmVhdGUgYSBob3Jpem9udGFsIGJhciBjaGFydApnZ3Bsb3Qoc3ViamVjdF9jb3VudCwgYWVzKHkgPSByZW9yZGVyKHN1YmplY3QsIG4pLCB4ID0gbikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpKSArCiAgbGFicyh5ID0gIlN1YmplY3QiLCB4ID0gIkNvdW50IiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFN1YmplY3RzIikKYGBgCk5vdGU6IFlvdSBzZWUgdGhhdCB0aGVyZSBhcmUgb3RoZXIgbm9uIG1hbmFnZW1lbnQgYXJlYXMgYWxzbyBsaW5rZWQgaGVyZS4gVGhhdCdzIGJlY2F1c2UgYSBsb3Qgb2YgdGhlIHBhcGVycyBoYXZlIGFsc28gYmVlbiBsaXN0ZWQgYXMgc2NpZW5jZSwgZW52aXJvbm1lbnQgYW5kIHNvY2lvbG9neSwgZXRjLiAKCgpUcnlpbmcgdG8gdW5kZXJzdGFuZCB0aGUgZGlzdHJpYnV0aW9uIG9mIGNvdW50cmllcyBub3cKYGBge3J9CiMgU2VwYXJhdGUgdGhlIHN1YmplY3RzIGludG8gaW5kaXZpZHVhbCByb3dzCmRhdGFfY291bnRyeSA8LSBkYXRhX25vbmJ1c2luZXNzICU+JQogICAgICAgICAgICAgICAgIHNlcGFyYXRlX3Jvd3MoY291bnRyeSwgc2VwID0gIjtcXHMqIikKCiMgQ291bnQgdGhlIG9jY3VycmVuY2VzIG9mIGVhY2ggc3ViamVjdApjb3VudHJ5X2NvdW50IDwtIGRhdGFfY291bnRyeSAlPiUKICAgICAgICAgICAgICAgICBjb3VudChjb3VudHJ5LCBzb3J0ID0gVFJVRSkKCiMgQ3JlYXRlIGEgaG9yaXpvbnRhbCBiYXIgY2hhcnQKZ2dwbG90KGNvdW50cnlfY291bnQsIGFlcyh5ID0gcmVvcmRlcihjb3VudHJ5LCBuKSwgeCA9IG4pKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNCkpICsKICAgIGxhYnMoeSA9ICJDb3VudHJ5IiwgeCA9ICJDb3VudCIsIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBDb3VudHJpZXMgLSBOb24gTWFuYWdlbWVudCIpCgpgYGAKCgpgYGB7cn0KbGVuZ3RoKHVuaXF1ZShjb3VudHJ5X2NvdW50JGNvdW50cnkpKQpgYGAKVGhlcmUgYXBwZWFyIHRvIGJlIGF1dGhvcnMgZnJvbSAxNzMgY291bnRyaWVzIHBhcnRpY2lwYXRpbmcgaGVyZS4gCgpgYGB7cn0KIyBTZXBhcmF0ZSB0aGUgc3ViamVjdHMgaW50byBpbmRpdmlkdWFsIHJvd3MKZGF0YV9jb3VudHJ5IDwtIGRhdGFfYnVzaW5lc3MgJT4lCiAgICAgICAgICAgICAgICAgc2VwYXJhdGVfcm93cyhjb3VudHJ5LCBzZXAgPSAiO1xccyoiKQoKIyBDb3VudCB0aGUgb2NjdXJyZW5jZXMgb2YgZWFjaCBzdWJqZWN0CmNvdW50cnlfY291bnQgPC0gZGF0YV9jb3VudHJ5ICU+JQogICAgICAgICAgICAgICAgIGNvdW50KGNvdW50cnksIHNvcnQgPSBUUlVFKQoKIyBDcmVhdGUgYSBob3Jpem9udGFsIGJhciBjaGFydApnZ3Bsb3QoY291bnRyeV9jb3VudCwgYWVzKHkgPSByZW9yZGVyKGNvdW50cnksIG4pLCB4ID0gbikpICsKICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA0KSkgKwogICAgbGFicyh5ID0gIkNvdW50cnkiLCB4ID0gIkNvdW50IiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIENvdW50cmllcyAtIE5vbiBNYW5hZ2VtZW50IikKCgpgYGAKCmBgYHtyfQpsZW5ndGgodW5pcXVlKGNvdW50cnlfY291bnQkY291bnRyeSkpCmBgYApUaGVyZSBhcHBlYXIgdG8gYmUgYXV0aG9ycyBmcm9tIDk0IGNvdW50cmllcyBwYXJ0aWNpcGF0aW5nIGhlcmUuIAoKVHJ5aW5nIHRvIHVuZGVyc3RhbmQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBpbnN0aXR1dGlvbnMgbm93CmBgYHtyfQojIFNlcGFyYXRlIHRoZSBzdWJqZWN0cyBpbnRvIGluZGl2aWR1YWwgcm93cwpkYXRhX2luc3RpdHV0aW9uIDwtIGRhdGFfbm9uYnVzaW5lc3MgJT4lCiAgICAgICAgICAgICAgICAgc2VwYXJhdGVfcm93cyhpbnN0aXR1dGlvbiwgc2VwID0gIjtcXHMqIikKCiMgQ291bnQgdGhlIG9jY3VycmVuY2VzIG9mIGVhY2ggc3ViamVjdAppbnN0aXR1dGlvbl9jb3VudCA8LSBkYXRhX2luc3RpdHV0aW9uICU+JQogICAgICAgICAgICAgICAgIGNvdW50KGluc3RpdHV0aW9uLCBzb3J0ID0gVFJVRSkKCmxlbmd0aCh1bmlxdWUoaW5zdGl0dXRpb25fY291bnQkaW5zdGl0dXRpb24pKQpgYGAKVGhlcmUgYXBwZWFyIHRvIGJlIGF1dGhvcnMgZnJvbSA3NzYxMCBpbnN0aXR1dGlvbnMgcGFydGljaXBhdGVkIGhlcmUuIAoKCmBgYHtyfQojIFNlcGFyYXRlIHRoZSBzdWJqZWN0cyBpbnRvIGluZGl2aWR1YWwgcm93cwpkYXRhX2luc3RpdHV0aW9uIDwtIGRhdGFfYnVzaW5lc3MgJT4lCiAgICAgICAgICAgICAgICAgc2VwYXJhdGVfcm93cyhpbnN0aXR1dGlvbiwgc2VwID0gIjtcXHMqIikKCiMgQ291bnQgdGhlIG9jY3VycmVuY2VzIG9mIGVhY2ggc3ViamVjdAppbnN0aXR1dGlvbl9jb3VudCA8LSBkYXRhX2luc3RpdHV0aW9uICU+JQogICAgICAgICAgICAgICAgIGNvdW50KGluc3RpdHV0aW9uLCBzb3J0ID0gVFJVRSkKCmxlbmd0aCh1bmlxdWUoaW5zdGl0dXRpb25fY291bnQkaW5zdGl0dXRpb24pKQpgYGAKVGhlcmUgYXBwZWFyIHRvIGJlIGF1dGhvcnMgZnJvbSA4MjQwIGluc3RpdHV0aW9ucyBwYXJ0aWNpcGF0ZWQgaGVyZS4gCgoKQ2hlY2tpbmcgb24gcmVwZWF0IG9mZmVuZGVycwpgYGB7cn0KIyBTZXBhcmF0ZSB0aGUgc3ViamVjdHMgaW50byBpbmRpdmlkdWFsIHJvd3MKZGF0YV9hdXRob3IgPC0gZGF0YV9ub25idXNpbmVzcyAlPiUKICAgICAgICAgICAgICAgICBzZXBhcmF0ZV9yb3dzKGF1dGhvciwgc2VwID0gIjtcXHMqIikKCiMgQ291bnQgdGhlIG9jY3VycmVuY2VzIG9mIGVhY2ggc3ViamVjdAphdXRob3JfY291bnQgPC0gZGF0YV9hdXRob3IgJT4lCiAgICAgICAgICAgICAgICAgY291bnQoYXV0aG9yLCBzb3J0ID0gVFJVRSkKCmF1dGhvcl9jb3VudF9ub25idXNpbmVzcyA8LWF1dGhvcl9jb3VudAoKbGVuZ3RoKHVuaXF1ZShhdXRob3JfY291bnQkYXV0aG9yKSkKYGBgClRoZXJlIGFyZSBhYm91dCAxLDIyLDU3MyB1bmlxdWUgYXV0aG9ycyBpbiB0aGUgbm9uIGJ1c2luZXNzIGRhdGFzZXQuCgpgYGB7cn0KbGVuZ3RoKHVuaXF1ZShhdXRob3JfY291bnQkYXV0aG9yKSkvbGVuZ3RoKGRhdGFfbm9uYnVzaW5lc3MkcmVjb3JkX2lkKQpgYGAKVGhlcmUgaGF2ZSBvbiBhdmVyYWdlIGJlZW4sIDIuODUgYXV0aG9ycyBwZXIgcGFwZXIuIAoKYGBge3J9Cmxlbmd0aCh1bmlxdWUoYXV0aG9yX2NvdW50JGF1dGhvcikpL2xlbmd0aChkYXRhX25vbmJ1c2luZXNzJHJlY29yZF9pZCkKYGBgCgpgYGB7cn0KIyBTdGVwIDE6IEFkZCBhIGNvbHVtbiB3aXRoIHRoZSBudW1iZXIgb2YgYXV0aG9ycyBwZXIgcHVibGljYXRpb24KZGF0YV9ub25idXNpbmVzcyA8LSBkYXRhX25vbmJ1c2luZXNzICU+JQogIG11dGF0ZSgKICAgIG51bV9hdXRob3JzID0gc2FwcGx5KHN0cnNwbGl0KGFzLmNoYXJhY3RlcihhdXRob3IpLCAiOyIpLCBsZW5ndGgpLAogICAgcHVibGljYXRpb25feWVhciA9IHllYXIob3JpZ2luYWxfcGFwZXJfZGF0ZSkKICApCgojIFN0ZXAgMjogR3JvdXAgYnkgcHVibGljYXRpb24geWVhciBhbmQgY2FsY3VsYXRlIHRoZSBhdmVyYWdlIG51bWJlciBvZiBhdXRob3JzCmF2ZXJhZ2VfYXV0aG9yc19wZXJfeWVhciA8LSBkYXRhX25vbmJ1c2luZXNzICU+JQogIGdyb3VwX2J5KHB1YmxpY2F0aW9uX3llYXIpICU+JQogIHN1bW1hcmlzZShhdmVyYWdlX2F1dGhvcnMgPSBtZWFuKG51bV9hdXRob3JzLCBuYS5ybSA9IFRSVUUpKQoKIyBQbG90dGluZyB0aGUgYXZlcmFnZSBudW1iZXIgb2YgYXV0aG9ycyBwZXIgeWVhcgpnZ3Bsb3QoYXZlcmFnZV9hdXRob3JzX3Blcl95ZWFyLCBhZXMoeCA9IHB1YmxpY2F0aW9uX3llYXIsIHkgPSBhdmVyYWdlX2F1dGhvcnMpKSArCiAgZ2VvbV9saW5lKCkgKyAgIyBMaW5lIHBsb3QKICBnZW9tX3BvaW50KCkgKyAjIEFkZGluZyBwb2ludHMgdG8gZWFjaCB5ZWFyCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKAogICAgdGl0bGUgPSAiQXZlcmFnZSBOdW1iZXIgb2YgQXV0aG9ycyBwZXIgUHVibGljYXRpb24gT3ZlciBZZWFycyIsCiAgICB4ID0gIlB1YmxpY2F0aW9uIFllYXIiLAogICAgeSA9ICJBdmVyYWdlIE51bWJlciBvZiBBdXRob3JzIgogICkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSAjIEFkanVzdGluZyB4LWF4aXMgbGFiZWxzIGZvciBiZXR0ZXIgcmVhZGFiaWxpdHkKICApKyAKICAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDE5OTAsIG1heChhdmVyYWdlX2F1dGhvcnNfcGVyX3llYXIkcHVibGljYXRpb25feWVhcikpKSAjIExpbWl0aW5nIHgtYXhpcyBmcm9tIDE5ODAgb253YXJkCgoKYGBgCgoKYGBge3J9CiMgU3RlcCAxOiBBZGQgYSBjb2x1bW4gd2l0aCB0aGUgbnVtYmVyIG9mIGF1dGhvcnMgcGVyIHB1YmxpY2F0aW9uCmRhdGFfYnVzaW5lc3MgPC0gZGF0YV9idXNpbmVzcyAlPiUKICBtdXRhdGUoCiAgICBudW1fYXV0aG9ycyA9IHNhcHBseShzdHJzcGxpdChhcy5jaGFyYWN0ZXIoYXV0aG9yKSwgIjsiKSwgbGVuZ3RoKSwKICAgIHB1YmxpY2F0aW9uX3llYXIgPSB5ZWFyKG9yaWdpbmFsX3BhcGVyX2RhdGUpCiAgKQoKIyBTdGVwIDI6IEdyb3VwIGJ5IHB1YmxpY2F0aW9uIHllYXIgYW5kIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZSBudW1iZXIgb2YgYXV0aG9ycwphdmVyYWdlX2F1dGhvcnNfcGVyX3llYXIgPC0gZGF0YV9idXNpbmVzcyAlPiUKICBncm91cF9ieShwdWJsaWNhdGlvbl95ZWFyKSAlPiUKICBzdW1tYXJpc2UoYXZlcmFnZV9hdXRob3JzID0gbWVhbihudW1fYXV0aG9ycywgbmEucm0gPSBUUlVFKSkKCiMgUGxvdHRpbmcgdGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIGF1dGhvcnMgcGVyIHllYXIKZ2dwbG90KGF2ZXJhZ2VfYXV0aG9yc19wZXJfeWVhciwgYWVzKHggPSBwdWJsaWNhdGlvbl95ZWFyLCB5ID0gYXZlcmFnZV9hdXRob3JzKSkgKwogIGdlb21fbGluZSgpICsgICMgTGluZSBwbG90CiAgZ2VvbV9wb2ludCgpICsgIyBBZGRpbmcgcG9pbnRzIHRvIGVhY2ggeWVhcgogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicygKICAgIHRpdGxlID0gIkF2ZXJhZ2UgTnVtYmVyIG9mIEF1dGhvcnMgcGVyIFB1YmxpY2F0aW9uIE92ZXIgWWVhcnMiLAogICAgeCA9ICJQdWJsaWNhdGlvbiBZZWFyIiwKICAgIHkgPSAiQXZlcmFnZSBOdW1iZXIgb2YgQXV0aG9ycyIKICApICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkgIyBBZGp1c3RpbmcgeC1heGlzIGxhYmVscyBmb3IgYmV0dGVyIHJlYWRhYmlsaXR5CiAgKSsgCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygxOTkwLCBtYXgoYXZlcmFnZV9hdXRob3JzX3Blcl95ZWFyJHB1YmxpY2F0aW9uX3llYXIpKSkgIyBMaW1pdGluZyB4LWF4aXMgZnJvbSAxOTgwIG9ud2FyZAoKCmBgYAoKUHJlcGFyaW5nIGEgam9pbnQgcGxvdApgYGB7cn0KIyBQcmVwYXJlIG5vbmJ1c2luZXNzIGRhdGEKZGF0YV9ub25idXNpbmVzcyA8LSBkYXRhX25vbmJ1c2luZXNzICU+JQogIG11dGF0ZSgKICAgIG51bV9hdXRob3JzID0gc2FwcGx5KHN0cnNwbGl0KGFzLmNoYXJhY3RlcihhdXRob3IpLCAiOyIpLCBsZW5ndGgpLAogICAgcHVibGljYXRpb25feWVhciA9IHllYXIob3JpZ2luYWxfcGFwZXJfZGF0ZSksCiAgICB0eXBlID0gIk5vbmJ1c2luZXNzIgogICkKCiMgUHJlcGFyZSBidXNpbmVzcyBkYXRhCmRhdGFfYnVzaW5lc3MgPC0gZGF0YV9idXNpbmVzcyAlPiUKICBtdXRhdGUoCiAgICBudW1fYXV0aG9ycyA9IHNhcHBseShzdHJzcGxpdChhcy5jaGFyYWN0ZXIoYXV0aG9yKSwgIjsiKSwgbGVuZ3RoKSwKICAgIHB1YmxpY2F0aW9uX3llYXIgPSB5ZWFyKG9yaWdpbmFsX3BhcGVyX2RhdGUpLAogICAgdHlwZSA9ICJCdXNpbmVzcyIKICApCgojIENvbWJpbmUgdGhlIGRhdGFzZXRzCmNvbWJpbmVkX2RhdGEgPC0gYmluZF9yb3dzKGRhdGFfbm9uYnVzaW5lc3MsIGRhdGFfYnVzaW5lc3MpCgojIEdyb3VwIGJ5IHB1YmxpY2F0aW9uIHllYXIgYW5kIHR5cGUsIHRoZW4gY2FsY3VsYXRlIHRoZSBhdmVyYWdlIG51bWJlciBvZiBhdXRob3JzCmF2ZXJhZ2VfYXV0aG9yc19wZXJfeWVhcl90eXBlIDwtIGNvbWJpbmVkX2RhdGEgJT4lCiAgZ3JvdXBfYnkocHVibGljYXRpb25feWVhciwgdHlwZSkgJT4lCiAgc3VtbWFyaXNlKGF2ZXJhZ2VfYXV0aG9ycyA9IG1lYW4obnVtX2F1dGhvcnMsIG5hLnJtID0gVFJVRSkpCgojIFBsb3R0aW5nIHRoZSBhdmVyYWdlIG51bWJlciBvZiBhdXRob3JzIHBlciB5ZWFyIGZvciBib3RoIHR5cGVzCmdncGxvdChhdmVyYWdlX2F1dGhvcnNfcGVyX3llYXJfdHlwZSwgYWVzKHggPSBwdWJsaWNhdGlvbl95ZWFyLCB5ID0gYXZlcmFnZV9hdXRob3JzLCBjb2xvciA9IHR5cGUpKSArCiAgZ2VvbV9saW5lKCkgKyAgIyBMaW5lIHBsb3QKICBnZW9tX3BvaW50KCkgKyAjIEFkZGluZyBwb2ludHMgdG8gZWFjaCB5ZWFyCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKAogICAgdGl0bGUgPSAiQXZlcmFnZSBOdW1iZXIgb2YgQXV0aG9ycyBwZXIgUmV0cmFjdGVkIFB1YmxpY2F0aW9uIE92ZXIgWWVhcnMiLAogICAgeCA9ICJQdWJsaWNhdGlvbiBZZWFyIiwKICAgIHkgPSAiQXZlcmFnZSBOdW1iZXIgb2YgQXV0aG9ycyIKICApICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkgIyBBZGp1c3RpbmcgeC1heGlzIGxhYmVscyBmb3IgYmV0dGVyIHJlYWRhYmlsaXR5CiAgKSsgCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMTk5MCwgbWF4KGF2ZXJhZ2VfYXV0aG9yc19wZXJfeWVhcl90eXBlJHB1YmxpY2F0aW9uX3llYXIpKSkgIwoKYGBgCgpGcm9tIHRoaXMsIGl0IGRvZXMgbG9vayBsaWtlIG1hbmFnZW1lbnQgcmVsYXRlZCBwdWJsaWNhdGlvbnMgKGFzIGNsYXNzaWZpZWQgYnkgdGhlIGF1dGhvcnMpIGRvZXMgbm90IHNlZW0gdG8gaGF2ZSBhcyBtYW55IGF1dGhvcnMgYXMgbm9uIG1hbmFnZW1lbnQgcmVsYXRlZCBhcnRpY2xlcy4gCgoKYGBge3J9CiMgUHJlcGFyZSBkYXRhCnllYXJseV9kYXRhIDwtIHJldF9pbnRfYWJkYyAlPiUKICBncm91cF9ieShyZXRyYWN0aW9uX3llYXIpICU+JQogIHN1bW1hcml6ZShhdmVyYWdlX2R1cmF0aW9uID0gbWVhbihkdXJhdGlvbl9pbl9tb250aHMsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIHJldHJhY3Rpb25fY291bnQgPSBuKCkpCgojIE5vcm1hbGl6ZSB0aGUgUmV0cmFjdGlvbkNvdW50IGZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbgptYXhfZHVyYXRpb24gPC0gbWF4KHllYXJseV9kYXRhJGF2ZXJhZ2VfZHVyYXRpb24sIG5hLnJtID0gVFJVRSkKbWF4X2NvdW50IDwtIG1heCh5ZWFybHlfZGF0YSRyZXRyYWN0aW9uX2NvdW50LCBuYS5ybSA9IFRSVUUpCnllYXJseV9kYXRhJE5vcm1hbGl6ZWRDb3VudCA8LSB5ZWFybHlfZGF0YSRyZXRyYWN0aW9uX2NvdW50IC8gbWF4X2NvdW50ICogbWF4X2R1cmF0aW9uCgpyZXRyYWN0aW9uc19tYW5hZ2VtZW50PC0gZ2dwbG90KHllYXJseV9kYXRhLCBhZXMoeCA9IHJldHJhY3Rpb25feWVhcikpICsKICBnZW9tX2xpbmUoYWVzKHkgPSBhdmVyYWdlX2R1cmF0aW9uLCBncm91cCA9IDEpLCBjb2xvciA9ICJibHVlIikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBhdmVyYWdlX2R1cmF0aW9uKSwgY29sb3IgPSAiYmx1ZSIpICsKICBnZW9tX2JhcihhZXMoeSA9IE5vcm1hbGl6ZWRDb3VudCksIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInJlZCIsIGFscGhhID0gMC41KSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygyMDAwLCBOQSkpICsKCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiQXZlcmFnZSBEdXJhdGlvbiBpbiBNb250aHMiLCAKICAgICAgICAgICAgICAgICAgICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+IC4gKiBtYXhfY291bnQgLyBtYXhfZHVyYXRpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiTnVtYmVyIG9mIFJldHJhY3Rpb25zIikpICsKICBsYWJzKHRpdGxlID0gIlJldHJhY3Rpb25zIG92ZXIgdGhlIFllYXJzOiBEdXJhdGlvbiBhbmQgQ291bnQgKEFCREMpIiwKICAgICAgIHggPSAiUmV0cmFjdGlvbiBZZWFyIikgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksICAjIENlbnRlci1hbGlnbiB0aGUgdGl0bGUKICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCAgIyBDZW50ZXItYWxpZ24gdGhlIHN1YnRpdGxlIGlmIHlvdSBoYXZlIG9uZQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSAgIyBDZW50ZXItYWxpZ24gdGhlIHgtYXhpcyBsYWJlbAogICkKCgpyZXRyYWN0aW9uc19tYW5hZ2VtZW50CmBgYAoKCkZyb20gdGhpcyBkYXRhIHNldCwgbGV0J3MgdHJ5IHRvIHB1bGwgb3V0IHRoZSBuYW1lcyBvZiBldmVyeSBhdXRob3IuLiBhbmQgc2VlIGlmIHRoZXJlIGFyZSAKMS4gcmVwZWF0IG9mZmVuZGVycwoyLiBIb3cgbWFueSB0b3RhbCBhdXRob3JzIGFyZSB0aGVyZSB3aXRoIHJldHJhY3Rpb24gcmVsYXRlZCBpc3N1ZXMKCgpgYGB7cn0KIyBFeHBhbmQgdGhlIGRhdGFzZXQgc28gZWFjaCByb3cgcmVwcmVzZW50cyBhIHJlY29yZC1hdXRob3IgY29tYmluYXRpb24KZXhwYW5kZWRfZGF0YXNldCA8LSByZXRfaW50X2FiZGMgJT4lCiAgc2VwYXJhdGVfcm93cyhhdXRob3IsIHNlcCA9ICI7IikgJT4lCiAgbXV0YXRlKGF1dGhvciA9IHRyaW13cyhhdXRob3IpKSAgIyBSZW1vdmUgYW55IGxlYWRpbmcvdHJhaWxpbmcgd2hpdGVzcGFjZQoKIyBDb3VudCB0aGUgbnVtYmVyIG9mIHJldHJhY3Rpb25zIGZvciBlYWNoIGF1dGhvcgphdXRob3JfcmV0cmFjdGlvbl9jb3VudHMgPC0gZXhwYW5kZWRfZGF0YXNldCAlPiUKICBncm91cF9ieShhdXRob3IpICU+JQogIHN1bW1hcmlzZShyZXRyYWN0aW9uX2NvdW50ID0gbigpKSAlPiUKICBmaWx0ZXIoYXV0aG9yICE9ICIiKSAgIyBSZW1vdmUgZW1wdHkgYXV0aG9yIGVudHJpZXMgaWYgYW55CgoKIyBEZWZpbmUgYSB0aHJlc2hvbGQgZm9yIHRoZSBtYXhpbXVtIG51bWJlciBvZiByZXRyYWN0aW9ucyBwZXIgYXV0aG9yCnRocmVzaG9sZCA9IDEwICAjIEFkanVzdCB0aGlzIG51bWJlciBiYXNlZCBvbiB5b3VyIGRhdGEgYW5kIG5lZWRzCgojIEZpbHRlciB0aGUgZGF0YSB0byBleGNsdWRlIG91dGxpZXJzCmZpbHRlcmVkX2F1dGhvcl9yZXRyYWN0aW9uX2NvdW50cyA8LSBhdXRob3JfcmV0cmFjdGlvbl9jb3VudHMgJT4lCiAgZmlsdGVyKHJldHJhY3Rpb25fY291bnQgPD0gdGhyZXNob2xkKQoKZ2dwbG90KGZpbHRlcmVkX2F1dGhvcl9yZXRyYWN0aW9uX2NvdW50cywgYWVzKHggPSByZXRyYWN0aW9uX2NvdW50KSkgKwpnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGZpbGwgPSAiYmx1ZSIsIGNvbG9yID0gImJsYWNrIikgKwpsYWJzKHRpdGxlID0gcGFzdGUoIkRpc3RyaWJ1dGlvbiBvZiBSZXRyYWN0aW9ucyBwZXIgQXV0aG9yIChMaW1pdGVkIHRvIiwgdGhyZXNob2xkLCAiUmV0cmFjdGlvbnMpIiksCnggPSAiTnVtYmVyIG9mIFJldHJhY3Rpb25zIiwKeSA9ICJDb3VudCBvZiBBdXRob3JzIikgKwp0aGVtZV9taW5pbWFsKCkKYGBgCkl0IGxvb2tzIGxpa2Ugc2VyaWFsIHJldHJhY3Rpb25zIGFyZSBub3QgdmVyeSBjb21tb25wbGFjZS4gVGhlcmUgYXJlIGhhcmRseSAyMDAgYXV0aG9ycyBhbW9uZyAyMjI5IHdobyBoYXZlIG11bHRpcGxlIGNvdW50cyBvZiByZXRyYWN0aW9uLiAKCiMjIExldCdzIHRyeSB0byBjcmVhdGUgYW4gYXV0aG9yIGF1dGhvciByZWxhdGlvbnNoaXAgbmV0d29yay4KCkJ1dCB0aGF0J3Mgbm90IHBvc3NpYmxlIHRvIGRvIHdpdGggdGhlIGxpbWl0ZWQgZGF0YSB0aGF0IHdlIGhhdmUgYWNjZXNzIHRvIGF0IHRoZSBtb21lbnQuIApXZSBhcmUgZ29pbmcgdG8gaGF2ZSB0byBleHBsb3JlIHdobyBhbGwgdGhlIGF1dGhvcnMgaGF2ZSBsaW5rZWQgdXAgd2l0aCBpbiB0aGUgcGFzdCBhc3dlbGwuIAoKT25lIG9mIHRoZSBpc3N1ZXMgdGhhdCBiZWNvbWVzIGluY3JlYXNpbmdseSBhcHBhcmVudCBpcyB0aGUgbmF0aW9uYWxpdHkgb2YgdGhlIHJldHJhY3Rpb25zLiBJdCBhcHBlYXJzIHRoYXQgbWFueSBvZiB0aGUgcmV0cmFjdGlvbnMgc3RlbSBmcm9tIG5hdGlvbnMgbGlrZSBDaGluYS4gCgpMZXQgbWUgc2hvdyB5b3UuIAoKYGBge3J9CgojIEVuc3VyZSB0aGUgJ2NvdW50cnknIGNvbHVtbiBpcyBhIGNoYXJhY3RlciB2ZWN0b3IgaWYgaXQgaXMgbm90IGFscmVhZHkKb3VyX2ludGVyZXN0IDwtIHJldF9pbnRfYWJkYyAlPiUKICBtdXRhdGUoY291bnRyeSA9IGFzLmNoYXJhY3Rlcihjb3VudHJ5KSkKCiMgJ2NvdW50cnknIGlzIGEgY29sdW1uIHdoZXJlIGNvdW50cmllcyBhcmUgc2VwYXJhdGVkIGJ5IHNlbWljb2xvbnMgKGFuZCBwb3NzaWJseSBmb2xsb3dlZCBieSBzcGFjZXMpCmRhdGFfY291bnRyeSA8LSBvdXJfaW50ZXJlc3QgJT4lCiAgc2VwYXJhdGVfcm93cyhjb3VudHJ5LCBzZXAgPSAiO1xccyoiKSAjIHNlcCByZWdleCBtYXRjaGVzIGEgc2VtaWNvbG9uIGZvbGxvd2VkIGJ5IGFueSBudW1iZXIgb2Ygc3BhY2VzCgojIENvdW50IHRoZSBvY2N1cnJlbmNlcyBvZiBlYWNoIGNvdW50cnkKY291bnRyeV9jb3VudCA8LSBkYXRhX2NvdW50cnkgJT4lCiAgY291bnQoY291bnRyeSwgc29ydCA9IFRSVUUpCgojIENyZWF0ZSBhIGhvcml6b250YWwgYmFyIGNoYXJ0CmdncGxvdChjb3VudHJ5X2NvdW50LCBhZXMoeCA9IHJlb3JkZXIoY291bnRyeSwgbiksIHkgPSBuKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgY29vcmRfZmxpcCgpICsgICMgRmxpcCB0aGUgY29vcmRpbmF0ZXMgdG8gbWFrZSB0aGUgYmFycyBob3Jpem9udGFsCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSxheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNikpICsgICMgQWRqdXN0IHRoZSBzaXplIGlmIG5lZWRlZAogIGxhYnMoeCA9ICJDb3VudHJ5IiwgeSA9ICJDb3VudCIsIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBDb3VudHJpZXMiKQpgYGAKCml0IGxvb2tzIGxpa2UgQ2hpbmEsIFVTLCBVSywgTmV0aGVybGFuZHMgYW5kIEluZGlhIGFyZSB0aGUga2V5IHNvdXJjZXMgb2YgcmV0cmFjdGlvbnMuIAoKQ2FuIGluIGJlIHRoYXQgdGhpcyBpcyBhIHByb2JsZW0gaXMgbG9jYXRlZCB0byB3aXRoaW4gY2VydGFpbiBjb3VudHJpZXM/IG9yIGlzIHRoaXMgYSB0cnVseSBjb3JzcyBjdWx0dXJhbCBpc3N1ZT8KCkxldCdzIHRyeSBhbmQgZG9pbmcgYSBRQVAgY29ycmVsYXRpb24gdG8gZmluZCBvdXQuIAoKCkNyZWF0aW5nIHJldHJhY3Rpb24tYXV0aG9yLWF1dGhvciBuZXR3b3JrCmBgYHtyfQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgd2hlcmUgZWFjaCByb3cgcmVwcmVzZW50cyBhIHNpbmdsZSBhdXRob3IgZm9yIGEgZ2l2ZW4gcmVjb3JkX2lkCmF1dGhvcl9yZWNvcmRzIDwtIG91cl9pbnRlcmVzdCAlPiUKICBzZXBhcmF0ZV9yb3dzKGF1dGhvciwgc2VwID0gIjsiKSAlPiUKICBkaXN0aW5jdChyZWNvcmRfaWQsIGF1dGhvcikKCiMgQ3JlYXRlIGEgc3F1YXJlIG1hdHJpeCBvZiBhdXRob3JzLCBpbml0aWFsaXplZCB0byB6ZXJvCnVuaXF1ZV9hdXRob3JzIDwtIHNvcnQodW5pcXVlKGF1dGhvcl9yZWNvcmRzJGF1dGhvcikpCmNvYXV0aG9yX3JldHJhY3Rpb25fbWF0cml4IDwtIG1hdHJpeCgwLCBucm93ID0gbGVuZ3RoKHVuaXF1ZV9hdXRob3JzKSwgbmNvbCA9IGxlbmd0aCh1bmlxdWVfYXV0aG9ycyksCiAgICAgICAgICAgICAgICAgICAgICAgIGRpbW5hbWVzID0gbGlzdCh1bmlxdWVfYXV0aG9ycywgdW5pcXVlX2F1dGhvcnMpKQoKIyBGaWxsIHRoZSBtYXRyaXggd2l0aCAxJ3Mgd2hlcmUgYXV0aG9ycyBzaGFyZSBhIHJlY29yZF9pZApmb3IgKGkgaW4gc2VxX2xlbihucm93KGF1dGhvcl9yZWNvcmRzKSkpIHsKICBmb3IgKGogaW4gc2VxX2xlbihucm93KGF1dGhvcl9yZWNvcmRzKSkpIHsKICAgIGlmIChhdXRob3JfcmVjb3JkcyRyZWNvcmRfaWRbaV0gPT0gYXV0aG9yX3JlY29yZHMkcmVjb3JkX2lkW2pdKSB7CiAgICAgIGNvYXV0aG9yX3JldHJhY3Rpb25fbWF0cml4W2F1dGhvcl9yZWNvcmRzJGF1dGhvcltpXSwgYXV0aG9yX3JlY29yZHMkYXV0aG9yW2pdXSA8LSAxCiAgICB9CiAgfQp9CgojIFJlbW92ZSBzZWxmLWxvb3BzIGlmIGRlc2lyZWQgKGF1dGhvcnMgY29tcGFyZWQgd2l0aCB0aGVtc2VsdmVzKQpkaWFnKGNvYXV0aG9yX3JldHJhY3Rpb25fbWF0cml4KSA8LSAwCgpgYGAKTm93IHdlIGhhdmUgYSBkYXRhc2V0IHdoaWNoIGhhcyBhbGwgdGhlIHJldHJhY3Rpb24gYXV0aG9yJ3MgcmV0cmFjdGlvbiBuZXR3b3JrLi4gQnV0IHRoZW4sIHRoaXMgaXMgb25seSB0aGUgcmV0cmFjdGVkIHBhcGVycywgYW5kIG5vdCB0aGUgcmVzdCBvZiBhbGwgdGhlIHBhcGVycyB0aGF0IHRoZXkgaGF2ZSB3b3JrZWQgb24uIAoKQnVpbGRpbmcgYW5vdGhlciBtYXRyaXggLSB0aGlzIHRpbWUgdG8gdGFsayBhYm91dCB0aGUgY291bnRyaWVzIHRoZSBhdXRob3JzIGFyZSBmcm9tLiAKYGBge3J9CiMgU3BsaXR0aW5nIHRoZSBhdXRob3IgZmllbGQgYXMgdGhlcmUgY291bGQgYmUgbXVsdGlwbGUgYXV0aG9ycyBwZXIgcmVjb3JkCmF1dGhvcl9jb3VudHJ5IDwtIG91cl9pbnRlcmVzdCAlPiUKICBzZXBhcmF0ZV9yb3dzKGF1dGhvciwgc2VwID0gIjsiKSAlPiUKICBkaXN0aW5jdChyZWNvcmRfaWQsIGF1dGhvciwgY291bnRyeSkKCiMgQ3JlYXRpbmcgYSBsaXN0IG9mIHVuaXF1ZSBhdXRob3JzCnVuaXF1ZV9hdXRob3JzIDwtIHNvcnQodW5pcXVlKGF1dGhvcl9jb3VudHJ5JGF1dGhvcikpCgojIENyZWF0aW5nIGFuIGVtcHR5IG1hdHJpeCB0byBzdG9yZSB0aGUgY29ubmVjdGlvbnMKYXV0aG9yX2NvdW50cnlfbWF0cml4IDwtIG1hdHJpeCgwLCBucm93ID0gbGVuZ3RoKHVuaXF1ZV9hdXRob3JzKSwgbmNvbCA9IGxlbmd0aCh1bmlxdWVfYXV0aG9ycykpCnJvd25hbWVzKGF1dGhvcl9jb3VudHJ5X21hdHJpeCkgPC0gdW5pcXVlX2F1dGhvcnMKY29sbmFtZXMoYXV0aG9yX2NvdW50cnlfbWF0cml4KSA8LSB1bmlxdWVfYXV0aG9ycwoKIyBGaWxsaW5nIHRoZSBtYXRyaXgKZm9yIChpIGluIDE6bGVuZ3RoKHVuaXF1ZV9hdXRob3JzKSkgewogIGZvciAoaiBpbiAxOmxlbmd0aCh1bmlxdWVfYXV0aG9ycykpIHsKICAgIGlmIChpICE9IGopIHsKICAgICAgIyBDaGVjayBpZiBhdXRob3JzIGkgYW5kIGogYXJlIGFzc29jaWF0ZWQgd2l0aCB0aGUgc2FtZSBjb3VudHJ5CiAgICAgIGNvbW1vbl9jb3VudHJpZXMgPC0gaW50ZXJzZWN0KGF1dGhvcl9jb3VudHJ5JGNvdW50cnlbYXV0aG9yX2NvdW50cnkkYXV0aG9yID09IHVuaXF1ZV9hdXRob3JzW2ldXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXV0aG9yX2NvdW50cnkkY291bnRyeVthdXRob3JfY291bnRyeSRhdXRob3IgPT0gdW5pcXVlX2F1dGhvcnNbal1dKQogICAgICBpZiAobGVuZ3RoKGNvbW1vbl9jb3VudHJpZXMpID4gMCkgewogICAgICAgIGF1dGhvcl9jb3VudHJ5X21hdHJpeFtpLCBqXSA8LSAxCiAgICAgICAgYXV0aG9yX2NvdW50cnlfbWF0cml4W2osIGldIDwtIDEgIyBNYXRyaXggaXMgc3ltbWV0cmljCiAgICAgIH0KICAgIH0KICB9Cn0KCmRpYWcoYXV0aG9yX2NvdW50cnlfbWF0cml4KSA8LSAwCmBgYAoKCgoKVHJ5aW5nIHRvIHVzZSBhc25pcGUgYW5kIHZlZ2FuIHRvZ2V0aGVyIHRvIHJ1biBhIFFBUCBjb3JyZWxhdGlvbi4gCgpgYGB7cn0KbGlicmFyeShhc25pcGUpCmxpYnJhcnkodmVnYW4pCnFhcF9yZXN1bHQgPC0gbWFudGVsKGNvYXV0aG9yX3JldHJhY3Rpb25fbWF0cml4LCBhdXRob3JfY291bnRyeV9tYXRyaXgsIHBlcm11dGF0aW9ucyA9IDEwMDApCnByaW50KHFhcF9yZXN1bHQpCgpgYGAKClRoaXMgdGVzdCBzdWdnZXN0cyB0aGF0IHRoZXJlIGlzIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgdGhvdWdoIHJlbGF0aXZlbHkgd2VhaywgcG9zaXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgY29hdXRob3IgcmV0cmFjdGlvbiBtYXRyaXggYW5kIHRoZSBhdXRob3IgY291bnRyeSBtYXRyaXguIApUaGlzIG1lYW5zIHRoYXQgdGhlcmUgaXMgc29tZSBsZXZlbCBvZiBhc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZSBwYXR0ZXJucyBvciByZWxhdGlvbnNoaXBzIHJlcHJlc2VudGVkIGJ5IHRoZSBjb3VudHJ5IHJlbGF0aW9uc2hpcCBtYXRyaXggYW5kIHRoZSByZXRyYWN0aW9uIHJlbGF0aW9uc2hpcCBtYXRyaXguCgpUaGlzIGlzIGludGVyZXN0aW5nLi4gCgpOb3csIG1heWJlIHRoZXJlIGlzIGEgc3Ryb25nZXIgcmVsYXRpb25zaGlwIHRvIGRldGVjdCBpZiB3ZSBjaGVjayB0aGUgaW5zdGl0dXRlIGxldmVsIHJlbGF0aW9ucy4gCgoKQ3JlYXRpbmcgYW4gaW5zdGl0dWlvbiByZWxhdGlvbnNoaXAgbWF0cml4LiAKYGBge3J9CiMgU3BsaXR0aW5nIHRoZSBhdXRob3IgZmllbGQgYXMgdGhlcmUgY291bGQgYmUgbXVsdGlwbGUgYXV0aG9ycyBwZXIgcmVjb3JkCmF1dGhvcl9pbnN0aXR1dGlvbiA8LSBvdXJfaW50ZXJlc3QgJT4lCiAgc2VwYXJhdGVfcm93cyhhdXRob3IsIHNlcCA9ICI7IikgJT4lCiAgZGlzdGluY3QocmVjb3JkX2lkLCBhdXRob3IsIGluc3RpdHV0aW9uKQoKIyBDcmVhdGluZyBhIGxpc3Qgb2YgdW5pcXVlIGF1dGhvcnMKdW5pcXVlX2F1dGhvcnMgPC0gc29ydCh1bmlxdWUoYXV0aG9yX2luc3RpdHV0aW9uJGF1dGhvcikpCgojIENyZWF0aW5nIGFuIGVtcHR5IG1hdHJpeCB0byBzdG9yZSB0aGUgY29ubmVjdGlvbnMKYXV0aG9yX2luc3RpdHV0aW9uX21hdHJpeCA8LSBtYXRyaXgoMCwgbnJvdyA9IGxlbmd0aCh1bmlxdWVfYXV0aG9ycyksIG5jb2wgPSBsZW5ndGgodW5pcXVlX2F1dGhvcnMpKQpyb3duYW1lcyhhdXRob3JfaW5zdGl0dXRpb25fbWF0cml4KSA8LSB1bmlxdWVfYXV0aG9ycwpjb2xuYW1lcyhhdXRob3JfaW5zdGl0dXRpb25fbWF0cml4KSA8LSB1bmlxdWVfYXV0aG9ycwoKIyBGaWxsaW5nIHRoZSBtYXRyaXgKZm9yIChpIGluIDE6bGVuZ3RoKHVuaXF1ZV9hdXRob3JzKSkgewogIGZvciAoaiBpbiAxOmxlbmd0aCh1bmlxdWVfYXV0aG9ycykpIHsKICAgIGlmIChpICE9IGopIHsKICAgICAgIyBDaGVjayBpZiBhdXRob3JzIGkgYW5kIGogYXJlIGFzc29jaWF0ZWQgd2l0aCB0aGUgc2FtZSBpbnN0aXR1dGlvbgogICAgICBjb21tb25fY291bnRyaWVzIDwtIGludGVyc2VjdChhdXRob3JfaW5zdGl0dXRpb24kaW5zdGl0dXRpb25bYXV0aG9yX2luc3RpdHV0aW9uJGF1dGhvciA9PSB1bmlxdWVfYXV0aG9yc1tpXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1dGhvcl9pbnN0aXR1dGlvbiRpbnN0aXR1dGlvblthdXRob3JfaW5zdGl0dXRpb24kYXV0aG9yID09IHVuaXF1ZV9hdXRob3JzW2pdXSkKICAgICAgaWYgKGxlbmd0aChjb21tb25fY291bnRyaWVzKSA+IDApIHsKICAgICAgICBhdXRob3JfaW5zdGl0dXRpb25fbWF0cml4W2ksIGpdIDwtIDEKICAgICAgICBhdXRob3JfaW5zdGl0dXRpb25fbWF0cml4W2osIGldIDwtIDEgIyBNYXRyaXggaXMgc3ltbWV0cmljCiAgICAgIH0KICAgIH0KICB9Cn0KCmRpYWcoYXV0aG9yX2luc3RpdHV0aW9uX21hdHJpeCkgPC0gMAoKYGBgCgoKT25jZSBhZ2FpbiwgVHJ5aW5nIHRvIHJ1biBhIFFBUCBjb3JyZWxhdGlvbi4gCmBgYHtyfQpxYXBfcmVzdWx0IDwtIG1hbnRlbChjb2F1dGhvcl9yZXRyYWN0aW9uX21hdHJpeCwgYXV0aG9yX2luc3RpdHV0aW9uX21hdHJpeCwgcGVybXV0YXRpb25zID0gMTAwMCkKcHJpbnQocWFwX3Jlc3VsdCkKYGBgCgoKVGhpcyBzdWdnZXN0cyBhIHZlcnkgc3Ryb25nIHBvc2l0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGNvYXV0aG9yX3JldHJhY3Rpb25fbWF0cml4IGFuZCB0aGUgYXV0aG9yX2luc3RpdHV0aW9uX21hdHJpeC4gVGhlIGV4dHJlbWVseSBsb3cgcC12YWx1ZSBpbmRpY2F0ZXMgdGhhdCB0aGlzIGNvcnJlbGF0aW9uIGlzIGhpZ2hseSB1bmxpa2VseSB0byBoYXZlIG9jY3VycmVkIGJ5IGNoYW5jZS4gVGhpcyBpbXBsaWVzIGEgc2lnbmlmaWNhbnQgYXNzb2NpYXRpb24gYmV0d2VlbiB0aGUgcGF0dGVybnMgb3IgcmVsYXRpb25zaGlwcyByZXByZXNlbnRlZCBpbiB0aGVzZSB0d28gbWF0cmljZXMsIHN1Z2dlc3RpbmcgdGhhdCB0aGUgY29hdXRob3JzaGlwIHJldHJhY3Rpb24gcGF0dGVybnMgYXJlIGNsb3NlbHkgcmVsYXRlZCB0byB0aGUgaW5zdGl0dXRpb25zIG9mIHRoZSBhdXRob3JzLgoKSSB0aGluayB3ZSBhcmUgZG9pbmcgc29tZXRoaW5nIHdyb25nIGluIHRoaXMgYXBwcm9hY2guIFRoZSBtYXRyaWNlcyBhcmUgY29ycmVsYXRlZCBiZWNhdXNlIG9mIGhvdyB0aGUgZGF0YSB3YXMgc291cmNlZC4gSSB3b25kZXIgd2h5IHRoZXJlIHdhcyBub3QgYSAxLjAwIGNvcnJlbGF0aW9uLgoKCkNyZWF0aW5nIGF1dGhvci1wdWJsaXNoZXIgbmV0d29yawpgYGB7cn0KIyBTcGxpdHRpbmcgdGhlIGF1dGhvciBmaWVsZCBhcyB0aGVyZSBjb3VsZCBiZSBtdWx0aXBsZSBhdXRob3JzIHBlciByZWNvcmQKYXV0aG9yX3NwbGl0IDwtIGV4cGFuZGVkX2RhdGFzZXQgJT4lCiAgc2VwYXJhdGVfcm93cyhhdXRob3IsIHNlcCA9ICI7IikgJT4lCiAgZGlzdGluY3QocmVjb3JkX2lkLCBhdXRob3IsIHB1Ymxpc2hlcikKCiMgQ3JlYXRpbmcgYSBsaXN0IG9mIHVuaXF1ZSBhdXRob3JzCnVuaXF1ZV9hdXRob3JzIDwtIHNvcnQodW5pcXVlKGF1dGhvcl9zcGxpdCRhdXRob3IpKQoKIyBDcmVhdGluZyBhbiBlbXB0eSBtYXRyaXggdG8gc3RvcmUgdGhlIGNvbm5lY3Rpb25zCmF1dGhvcl9wdWJsaXNoZXJfbWF0cml4IDwtIG1hdHJpeCgwLCBucm93ID0gbGVuZ3RoKHVuaXF1ZV9hdXRob3JzKSwgbmNvbCA9IGxlbmd0aCh1bmlxdWVfYXV0aG9ycykpCnJvd25hbWVzKGF1dGhvcl9wdWJsaXNoZXJfbWF0cml4KSA8LSB1bmlxdWVfYXV0aG9ycwpjb2xuYW1lcyhhdXRob3JfcHVibGlzaGVyX21hdHJpeCkgPC0gdW5pcXVlX2F1dGhvcnMKCiMgRmlsbGluZyB0aGUgbWF0cml4CmZvciAoaSBpbiAxOmxlbmd0aCh1bmlxdWVfYXV0aG9ycykpIHsKICBmb3IgKGogaW4gMTpsZW5ndGgodW5pcXVlX2F1dGhvcnMpKSB7CiAgICBpZiAoaSAhPSBqKSB7CiAgICAgICMgQ2hlY2sgaWYgYXV0aG9ycyBpIGFuZCBqIGhhdmUgcHVibGlzaGVkIHdpdGggdGhlIHNhbWUgcHVibGlzaGVyCiAgICAgIGNvbW1vbl9wdWJsaXNoZXJzIDwtIGludGVyc2VjdChhdXRob3Jfc3BsaXQkcHVibGlzaGVyW2F1dGhvcl9zcGxpdCRhdXRob3IgPT0gdW5pcXVlX2F1dGhvcnNbaV1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXV0aG9yX3NwbGl0JHB1Ymxpc2hlclthdXRob3Jfc3BsaXQkYXV0aG9yID09IHVuaXF1ZV9hdXRob3JzW2pdXSkKICAgICAgaWYgKGxlbmd0aChjb21tb25fcHVibGlzaGVycykgPiAwKSB7CiAgICAgICAgYXV0aG9yX3B1Ymxpc2hlcl9tYXRyaXhbaSwgal0gPC0gMQogICAgICAgIGF1dGhvcl9wdWJsaXNoZXJfbWF0cml4W2osIGldIDwtIDEgIyBNYXRyaXggaXMgc3ltbWV0cmljCiAgICAgIH0KICAgIH0KICB9Cn0KCmBgYAoKCk9uY2UgYWdhaW4sIFRyeWluZyB0byBydW4gYSBRQVAgY29ycmVsYXRpb24uIFRoaXMgdGltZSB0byBzZWUgaWYgdGhlIGF1dGhvci1wdWJsaXNoZXIgcmVsYXRpb25zaGlwIGhhcyBzb21lIGltcGFjdC4uCmBgYHtyfQpxYXBfcmVzdWx0IDwtIG1hbnRlbChjb2F1dGhvcl9yZXRyYWN0aW9uX21hdHJpeCwgYXV0aG9yX3B1Ymxpc2hlcl9tYXRyaXgsIHBlcm11dGF0aW9ucyA9IDEwMDApCnByaW50KHFhcF9yZXN1bHQpCmBgYAoKVGhlIHRlc3Qgc3VnZ2VzdHMgdGhhdCB0aGVyZSBpcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIGFsYmVpdCB3ZWFrLCBwb3NpdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBwYXR0ZXJucyBvZiBjb2F1dGhvcnNoaXAgcmV0cmFjdGlvbiBhbmQgYXV0aG9yIHB1Ymxpc2hlciBhc3NvY2lhdGlvbnMgcmVwcmVzZW50ZWQgaW4gdGhlIHR3byBtYXRyaWNlcy4gSG93ZXZlciwgZ2l2ZW4gdGhlIGxvdyBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCwgdGhlIHN0cmVuZ3RoIG9mIHRoaXMgYXNzb2NpYXRpb24gaXMgbm90IHZlcnkgc3Ryb25nLgoKCkknbSBqdXN0IHRyeWluZyBhIGZldyBvdGhlciB0aGluZ3MgaGVyZS4gCgpDcmVhdGluZyBhdXRob3Itam91cm5hbCBuZXR3b3JrCmBgYHtyfQojIFNwbGl0dGluZyB0aGUgYXV0aG9yIGZpZWxkIGFzIHRoZXJlIGNvdWxkIGJlIG11bHRpcGxlIGF1dGhvcnMgcGVyIHJlY29yZAphdXRob3Jfc3BsaXQgPC0gZXhwYW5kZWRfZGF0YXNldCAlPiUKICBzZXBhcmF0ZV9yb3dzKGF1dGhvciwgc2VwID0gIjsiKSAlPiUKICBkaXN0aW5jdChyZWNvcmRfaWQsIGF1dGhvciwgam91cm5hbCkKCiMgQ3JlYXRpbmcgYSBsaXN0IG9mIHVuaXF1ZSBhdXRob3JzCnVuaXF1ZV9hdXRob3JzIDwtIHNvcnQodW5pcXVlKGF1dGhvcl9zcGxpdCRhdXRob3IpKQoKIyBDcmVhdGluZyBhbiBlbXB0eSBtYXRyaXggdG8gc3RvcmUgdGhlIGNvbm5lY3Rpb25zCmF1dGhvcl9qb3VybmFsX21hdHJpeCA8LSBtYXRyaXgoMCwgbnJvdyA9IGxlbmd0aCh1bmlxdWVfYXV0aG9ycyksIG5jb2wgPSBsZW5ndGgodW5pcXVlX2F1dGhvcnMpKQpyb3duYW1lcyhhdXRob3Jfam91cm5hbF9tYXRyaXgpIDwtIHVuaXF1ZV9hdXRob3JzCmNvbG5hbWVzKGF1dGhvcl9qb3VybmFsX21hdHJpeCkgPC0gdW5pcXVlX2F1dGhvcnMKCiMgRmlsbGluZyB0aGUgbWF0cml4CmZvciAoaSBpbiAxOmxlbmd0aCh1bmlxdWVfYXV0aG9ycykpIHsKICBmb3IgKGogaW4gMTpsZW5ndGgodW5pcXVlX2F1dGhvcnMpKSB7CiAgICBpZiAoaSAhPSBqKSB7CiAgICAgICMgQ2hlY2sgaWYgYXV0aG9ycyBpIGFuZCBqIGhhdmUgcHVibGlzaGVkIHdpdGggdGhlIHNhbWUgam91cm5hbAogICAgICBjb21tb25fam91cm5hbHMgPC0gaW50ZXJzZWN0KGF1dGhvcl9zcGxpdCRqb3VybmFsW2F1dGhvcl9zcGxpdCRhdXRob3IgPT0gdW5pcXVlX2F1dGhvcnNbaV1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXV0aG9yX3NwbGl0JGpvdXJuYWxbYXV0aG9yX3NwbGl0JGF1dGhvciA9PSB1bmlxdWVfYXV0aG9yc1tqXV0pCiAgICAgIGlmIChsZW5ndGgoY29tbW9uX2pvdXJuYWxzKSA+IDApIHsKICAgICAgICBhdXRob3Jfam91cm5hbF9tYXRyaXhbaSwgal0gPC0gMQogICAgICAgIGF1dGhvcl9qb3VybmFsX21hdHJpeFtqLCBpXSA8LSAxICMgTWF0cml4IGlzIHN5bW1ldHJpYwogICAgICB9CiAgICB9CiAgfQp9CgpgYGAKCgpPbmNlIGFnYWluLCBUcnlpbmcgdG8gcnVuIGEgUUFQIGNvcnJlbGF0aW9uLiBUaGlzIHRpbWUgdG8gc2VlIGlmIHRoZSBhdXRob3Itam91cm5hbCByZWxhdGlvbnNoaXAgaGFzIHNvbWUgaW1wYWN0Li4KYGBge3J9CnFhcF9yZXN1bHQgPC0gbWFudGVsKGNvYXV0aG9yX3JldHJhY3Rpb25fbWF0cml4LCBhdXRob3Jfam91cm5hbF9tYXRyaXgsIHBlcm11dGF0aW9ucyA9IDEwMDApCnByaW50KHFhcF9yZXN1bHQpCmBgYAoKRG9pbmcgYSBzdWJqZWN0LWF1dGhvciByZWxhdGlvbnNoaXAKYGBge3J9CgojIFNwbGl0dGluZyB0aGUgYXV0aG9yIGFuZCBzdWJqZWN0IGZpZWxkcyBhcyB0aGVyZSBjb3VsZCBiZSBtdWx0aXBsZSBhdXRob3JzIGFuZCBzdWJqZWN0cyBwZXIgcmVjb3JkCmF1dGhvcl9zdWJqZWN0X3NwbGl0IDwtIGV4cGFuZGVkX2RhdGFzZXQgJT4lCiAgc2VwYXJhdGVfcm93cyhhdXRob3IsIHN1YmplY3QsIHNlcCA9ICI7IikgJT4lCiAgZGlzdGluY3QocmVjb3JkX2lkLCBhdXRob3IsIHN1YmplY3QpCgojIENyZWF0aW5nIGEgbGlzdCBvZiB1bmlxdWUgYXV0aG9ycyBhbmQgc3ViamVjdHMKdW5pcXVlX2F1dGhvcnMgPC0gc29ydCh1bmlxdWUoYXV0aG9yX3N1YmplY3Rfc3BsaXQkYXV0aG9yKSkKdW5pcXVlX3N1YmplY3RzIDwtIHNvcnQodW5pcXVlKGF1dGhvcl9zdWJqZWN0X3NwbGl0JHN1YmplY3QpKQoKIyBDcmVhdGluZyBhbiBlbXB0eSBtYXRyaXggdG8gc3RvcmUgdGhlIGNvbm5lY3Rpb25zCmF1dGhvcl9zdWJqZWN0X21hdHJpeCA8LSBtYXRyaXgoMCwgbnJvdyA9IGxlbmd0aCh1bmlxdWVfYXV0aG9ycyksIG5jb2wgPSBsZW5ndGgodW5pcXVlX2F1dGhvcnMpKQpyb3duYW1lcyhhdXRob3Jfc3ViamVjdF9tYXRyaXgpIDwtIHVuaXF1ZV9hdXRob3JzCmNvbG5hbWVzKGF1dGhvcl9zdWJqZWN0X21hdHJpeCkgPC0gdW5pcXVlX2F1dGhvcnMKCiMgRmlsbGluZyB0aGUgbWF0cml4CmZvciAoaSBpbiAxOmxlbmd0aCh1bmlxdWVfYXV0aG9ycykpIHsKICBmb3IgKGogaW4gMTpsZW5ndGgodW5pcXVlX2F1dGhvcnMpKSB7CiAgICBpZiAoaSAhPSBqKSB7CiAgICAgICMgQ2hlY2sgaWYgYXV0aG9ycyBpIGFuZCBqIGhhdmUgcHVibGlzaGVkIGluIHRoZSBzYW1lIHN1YmplY3QKICAgICAgY29tbW9uX3N1YmplY3RzIDwtIGludGVyc2VjdChhdXRob3Jfc3ViamVjdF9zcGxpdCRzdWJqZWN0W2F1dGhvcl9zdWJqZWN0X3NwbGl0JGF1dGhvciA9PSB1bmlxdWVfYXV0aG9yc1tpXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXV0aG9yX3N1YmplY3Rfc3BsaXQkc3ViamVjdFthdXRob3Jfc3ViamVjdF9zcGxpdCRhdXRob3IgPT0gdW5pcXVlX2F1dGhvcnNbal1dKQogICAgICBpZiAobGVuZ3RoKGNvbW1vbl9zdWJqZWN0cykgPiAwKSB7CiAgICAgICAgYXV0aG9yX3N1YmplY3RfbWF0cml4W2ksIGpdIDwtIDEKICAgICAgICBhdXRob3Jfc3ViamVjdF9tYXRyaXhbaiwgaV0gPC0gMSAjIE1hdHJpeCBpcyBzeW1tZXRyaWMKICAgICAgfQogICAgfQogIH0KfQpgYGAKCgpgYGB7cn0KcWFwX3Jlc3VsdCA8LSBtYW50ZWwoYXV0aG9yX3N1YmplY3RfbWF0cml4LCBhdXRob3Jfam91cm5hbF9tYXRyaXgsIHBlcm11dGF0aW9ucyA9IDEwMDApCnByaW50KHFhcF9yZXN1bHQpCmBgYAoKCg==